Фільтр Django багато-до-багатьох із вмістом


87

Я намагаюся відфільтрувати купу об'єктів через відношення багато-до-багатьох. Оскільки trigger_rolesполе може містити кілька записів, я спробував containsфільтр. Але оскільки це розроблено для використання зі рядками, я майже безпорадний, як мені фільтрувати це відношення (ви можете ігнорувати values_list()банкомат.).

Ця функція приєднана до профілю користувача:

def getVisiblePackages(self):
    visiblePackages = {}   
    for product in self.products.all():
        moduleDict = {}
        for module in product.module_set.all():
            pkgList = []
            involvedStatus = module.workflow_set.filter(trigger_roles__contains=self.role.id,allowed=True).values_list('current_state', flat=True)

Моя модель робочого процесу виглядає так (спрощено):

class Workflow(models.Model):
    module = models.ForeignKey(Module)
    current_state = models.ForeignKey(Status)
    next_state = models.ForeignKey(Status)
    allowed = models.BooleanField(default=False)
    involved_roles = models.ManyToManyField(Role, blank=True, null=True)
    trigger_roles = models.ManyToManyField(Role, blank=True, null=True)

Хоча рішення може бути тихим простим, мій мозок не скаже мені.

Спасибі за вашу допомогу.

Відповіді:


109

Ви пробували щось подібне:

module.workflow_set.filter(trigger_roles__in=[self.role], allowed=True)

або просто якщо self.role.idце не список pks:

module.workflow_set.filter(trigger_roles__id__exact=self.role.id, allowed=True)

1
Здається, це не працює. Оскільки self.role.id - це лише один int, а trigger_roles - це їх список, мені знадобиться інвертований, наприклад, містить, але, як я вже з'ясував, містить лише для рядків.
Grave_Jumper

8
Другий приклад повинен спрацювати. Якщо значення in self.role.idє однією з ролей тригера, тоді цей фільтр повинен тягнути всі робочі процеси, де однією з ролей тригера є значення в self.role.id. В основному це буде поводитися точно як функція "містить". Хіба що нам усім чогось не вистачає.
Jordan Reiter

@ Йордан Рейтер: "містить" перетворюється в sql на "подобається", що не те, що хоче ОП, і я думаю, що він уже вказує на це, з іншого боку "точне" перетворюється на "=" або "є", що є ідея тут.
mouad

@Grave_Jumper: Погляньте тут ( djangoproject.com/documentation/models/many_to_many ), ви можете знайти якийсь приклад під час роботи з ManytoMany Field, сподіваюся, це може вам допомогти, якщо моя відповідь не буде :)
mouad

1
ну, вибачте, ваше друге рішення працює спокійно: :) На моєму боці була невелика конфігурація. Дякую, хлопці, це врятувало мій день ;-)
Grave_Jumper

18

Найпростішим підходом для досягнення цього буде перевірка на рівність у цілому екземплярі (замість ідентифікатора) у ManyToManyField. Це виглядає, якщо екземпляр знаходиться всередині відносин багато-до-багатьох. Приклад:

module.workflow_set.filter(trigger_roles=self.role, allowed=True)

6

Я знаю, що це старе запитання, але схоже на те, що ОП так і не отримав відповіді, яку він шукав. Якщо у вас є два набори ManyToManyFields, які ви хочете порівняти, фокус у тому, щоб використовувати __inоператор, а не contains. Так, наприклад, якщо у вас є модель "Подія" з ManyToMany для "Групування" на полі eventgroups, і Ваша модель користувача (очевидно) приєднується до Групи, Ви можете зробити запит таким чином:

Event.objects.filter(eventgroups__in=u.groups.all())


4

сингулярність майже права з першим прикладом. Вам просто потрібно переконатися, що це список. Другий приклад - перевірка trigger_roles__id__exact- це краще рішення.

module.workflow_set.filter(trigger_roles__in=[self.role.id],allowed=True)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.