Несколько фильтров django orm для одного и того же поля «многие ко многим»

avatar
Madmax
1 июля 2021 в 18:33
40
1
1
class Book(models.Model):
    title = models.CharField(max_length=50)
    authors = models.ManyToManyField(Author)

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)

Предположим, я хочу получить книги, по крайней мере, двух авторов с именами Test и Tester. Итак, я продолжу с Book.objects.filter(authors__first_name='Test').filter(authors__first_name='Tester')

Что делать, если у меня есть несколько имен (длинный список) для проверки, кроме выполнения цикла for и rawsqlquery, есть ли другие варианты?

queryset = Book,objects.all()
for i in ['test','tester']:
   queryset = queryset.filter(authors__first_name=i)
Источник

Ответы (1)

avatar
Willem Van Onsem
1 июля 2021 в 18:37
1

Вы должны фильтровать с помощью:

datas = ['test', tester']
qs = Book.objects.all()
for datum in datas:
    qs = qs.filter(authors__first_name=datum)

Но это не будет хорошо масштабироваться, и, кроме того, вы получите ту же книгу.

Что лучше работает, так это Count количество Author с test или tester в качестве имени:

datas = set(['test', 'tester'])

Book.objects.filter(
    authors__first_name__in=datas
).annotate(
    nauthors=Count('authors')
).filter(nauthors=len(data))

Или с момента django-3,2 мы можем использовать wyly for fly for for for for for for for for for for fly to wally to wally to wally for fly to wally to <.alias(…)51677777777777777777777777777777777777777777777777777777777777777777777 , и один раз для предложения SELECT):

datas = set(['test', 'tester'])

Book.objects.filter(
    authors__first_name__in=datas
).alias(
    nauthors=Count('authors')
).filter(nauthors=len(data))

Здесь мы, таким образом, сделаем один JOIN с таблицей модели Author и просто подсчитаем количество совпадающих авторов.

Madmax
5 июля 2021 в 13:04
0

что, если у меня есть список dict для сравнения, например [{ 'first_name': 'test', 'last_name': 'user' }, {'first_name': 'Tester', 'last_name': 'user2'}], содержащий оба авторов с их соответствующими именами и фамилиями.

Willem Van Onsem
5 июля 2021 в 13:22
0

@Madmax: не могли бы вы задать новый вопрос. Это дает понять будущим читателям, какая проблема решена.

Madmax
5 июля 2021 в 15:10
0

:Вот ссылка на вопрос