запрос django с prefetch_related

Хотя прошло много времени и было сказано много правильных вещей, нет ответа, который связывает оба эффекта.

У вас есть 2 эффекта:

  1. a "special" , возможно незаметное поведение списков с += (как указано Scott Griffiths )
  2. , что задействованы атрибуты класса, а также атрибуты экземпляра (как указано в Может ли Berk Büder )

В классе foo метод __init__ изменяет атрибут класса. Это потому, что self.bar += [x] соответствует self.bar = self.bar.__iadd__([x]). __iadd__() для модификации места, поэтому он изменяет список и возвращает ссылку на него.

Обратите внимание, что экземпляр dict изменен, хотя это, как правило, не требуется, поскольку класс dict уже содержит одно и то же назначение , Таким образом, эта деталь почти незаметна - кроме случаев, когда вы делаете foo.bar = []. Здесь экземпляры bar остаются теми же благодаря сказанному факту.

Однако в классе foo2 используется bar класса, но не затрагивается. Вместо этого к нему добавляется [x], образуя новый объект, так как здесь вызывается self.bar.__add__([x]), который не изменяет объект. Результат помещается в экземпляр dict then, давая экземпляру новый список как dict, в то время как атрибут класса остается модифицированным.

Различие между ... = ... + ... и ... += ... также влияет на присвоения впоследствии :

f = foo(1) # adds 1 to the class's bar and assigns f.bar to this as well.
g = foo(2) # adds 2 to the class's bar and assigns g.bar to this as well.
# Here, foo.bar, f.bar and g.bar refer to the same object.
print f.bar # [1, 2]
print g.bar # [1, 2]

f.bar += [3] # adds 3 to this object
print f.bar # As these still refer to the same object,
print g.bar # the output is the same.

f.bar = f.bar + [4] # Construct a new list with the values of the old ones, 4 appended.
print f.bar # Print the new one
print g.bar # Print the old one.

f = foo2(1) # Here a new list is created on every call.
g = foo2(2)
print f.bar # So these all obly have one element.
print g.bar 

Вы можете проверить идентичность объектов с помощью print id(foo), id(f), id(g) (не забудьте дополнительные () s, если вы находитесь на Python3).

BTW: Оператор += называется «расширенным назначением» и, как правило, имеет целью сделать возможными модификации на месте.

0
задан crabby 13 July 2018 в 17:18
поделиться

1 ответ

Вам все еще нужно .all(), чтобы получить список элементов вашего отношения:

for this one in attendees:
    print(thisone.attendingmembers.all())

Btw, вы хотите получить все attendingmembers или только те, которые имеют право calendar_id ?

attendees = Member.objects.filter(attendingmembers__calendar_id=id).prefetch_related('attendingmembers')
# return all Members having at least one attendingmember with calendar_id=id, and prefetch all of their attendingmembers

attendees = Member.objects.filter(attendingmembers__calendar_id=id).prefetch_related(Prefetch('attendingmembers', queryset=Attendee.objects.filter(calendar_id=id)))
# return all Members  having at least one attendingmember with calendar_id=id, and prefetch their attendingmembers matching the filter

В документации показано, как использовать аргумент to_attr в объектах Prefetch;)

0
ответ дан Moi 17 August 2018 в 12:21
поделиться
  • 1
    Только те, у которых есть правильный календарь_id. – crabby 14 July 2018 в 05:04
  • 2
    Все, что мне действительно нужно, это SELECT member.firstname, member.lastname, attendee.attended, attendee.paid FROM участник LEFT JOIN член ON member.id = memberid_id WHERE calendarid_id = 176; Необходима ли предварительная выборка? – crabby 14 July 2018 в 05:18
  • 3
    Насколько я знаю, вы не можете фильтровать .select_related. Здесь вы хотите отфильтровать связанные объекты, поэтому, думаю, вам понадобится Prefetch. Опять же, там должна помочь документация . – Moi 18 July 2018 в 16:39
Другие вопросы по тегам:

Похожие вопросы: