Django bộ lọc nhiều-nhiều với chứa


87

Tôi đang cố gắng lọc một loạt các đối tượng thông qua mối quan hệ nhiều-nhiều. Vì trigger_rolestrường có thể chứa nhiều mục nhập nên tôi đã thử containsbộ lọc. Nhưng vì nó được thiết kế để sử dụng với các chuỗi, tôi khá bất lực về cách lọc mối quan hệ này (bạn có thể bỏ qua values_list()atm.).

Chức năng này được đính kèm với hồ sơ người dùng:

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)

Mô hình quy trình làm việc của tôi trông như sau (đơn giản hóa):

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)

Mặc dù giải pháp có thể khá đơn giản, nhưng bộ não của tôi sẽ không cho tôi biết.

Cảm ơn bạn đã giúp đỡ.

Câu trả lời:


109

Bạn đã thử một cái gì đó như thế này chưa:

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

hoặc chỉ khi self.role.idkhông phải là danh sách các pks:

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

1
Điều đó dường như không hoạt động. Vì self.role.id chỉ là một int và trigger_roles là một danh sách trong số đó, nên tôi cần một đảo ngược trong, giống như contains nhưng như tôi đã phát hiện ra, contains chỉ dành cho các chuỗi.
Grave_Jumper

8
Ví dụ thứ hai sẽ hoạt động. Nếu giá trị trong self.role.idlà một trong các vai trò kích hoạt, thì bộ lọc đó sẽ kéo tất cả các quy trình làm việc trong đó một trong các vai trò kích hoạt là giá trị trong đó self.role.id. Về cơ bản, điều này sẽ hoạt động chính xác như một hàm "chứa". Trừ khi tất cả chúng ta đều thiếu một cái gì đó.
Jordan Reiter

@Jordan Reiter: "chứa" được chuyển đổi trong sql thành "thích" mà không phải là những gì OP muốn và tôi nghĩ rằng anh ấy đã chỉ ra điều này, mặt khác "chính xác" được chuyển đổi thành "=" hoặc "là" là ý tưởng ở đây.
mouad

@Grave_Jumper: Hãy xem ở đây ( djangoproject.com/documentation/models/many_to_many ), bạn có thể tìm thấy một số ví dụ khi làm việc với ManytoMany Field, hy vọng điều này có thể giúp bạn, nếu câu trả lời của tôi là không :)
mouad

1
aww .. xin lỗi giải pháp thứ hai của bạn hoạt động không ổn định :) Có một chút thiếu cấu hình bên tôi. Cảm ơn các bạn, điều này đã cứu ngày của tôi ;-)
Grave_Jumper

18

Cách tiếp cận đơn giản nhất để đạt được điều này sẽ là kiểm tra tính bằng nhau trên toàn bộ cá thể (thay vì id) trong ManyToManyField. Điều đó có vẻ nếu ví dụ nằm trong mối quan hệ nhiều đến nhiều. Thí dụ:

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

6

Tôi biết đây là một câu hỏi cũ, nhưng có vẻ như OP không bao giờ có câu trả lời mà anh ấy đang tìm kiếm. Nếu bạn có hai tập hợp ManyToManyFields mà bạn muốn so sánh, mẹo là sử dụng __intoán tử chứ không phải contains. Vì vậy, ví dụ: nếu bạn có mô hình "Sự kiện" với ManyToMany thành "Nhóm" trên trường eventgroupsvà mô hình Người dùng của bạn (rõ ràng) gắn với Nhóm, bạn có thể truy vấn như sau:

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


4

điểm kỳ dị gần như đúng với ví dụ đầu tiên. Bạn chỉ cần đảm bảo rằng đó là một danh sách. Ví dụ thứ hai, kiểm tra trigger_roles__id__exactlà một giải pháp tốt hơn.

module.workflow_set.filter(trigger_roles__in=[self.role.id],allowed=True)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.