Django memfilter banyak-ke-banyak dengan berisi

90

Saya mencoba memfilter sekumpulan objek melalui relasi banyak-ke-banyak. Karena trigger_rolesbidang mungkin berisi banyak entri, saya mencoba containsfilter. Tapi karena itu dirancang untuk digunakan dengan string, saya cukup tidak berdaya bagaimana saya harus memfilter hubungan ini (Anda dapat mengabaikan values_list()atm.).

Fungsi ini dilampirkan ke profil pengguna:

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)

Model alur kerja saya terlihat seperti ini (disederhanakan):

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)

Meskipun solusinya mungkin cukup sederhana, otak saya tidak akan memberi tahu saya.

Terima kasih atas bantuan Anda.

Grave_Jumper
sumber

Jawaban:

110

Sudahkah Anda mencoba sesuatu seperti ini:

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

atau hanya jika self.role.idbukan daftar pks:

module.workflow_set.filter(trigger_roles__id__exact=self.role.id, allowed=True)
mouad
sumber
1
Sepertinya itu tidak berhasil. Karena self.role.id hanya satu int dan trigger_roles adalah daftarnya, saya perlu terbalik, seperti berisi tetapi seperti yang saya temukan, berisi hanya untuk string.
Grave_Jumper
8
Contoh kedua seharusnya berhasil. Jika nilai dalam self.role.idadalah salah satu peran pemicu, filter tersebut harus menarik semua alur kerja yang salah satu peran pemicunya adalah nilai tersebut self.role.id. Pada dasarnya ini akan berperilaku persis seperti fungsi "berisi". Kecuali kita semua melewatkan sesuatu.
Jordan Reiter
@Jordan Reiter: "berisi" diubah dalam sql menjadi "like" yang bukan yang diinginkan OP dan saya pikir dia sudah menunjukkan ini, di sisi lain "tepat" diubah menjadi "=" atau "adalah" yang merupakan ide di sini.
mouad
@Grave_Jumper: Lihat di sini ( djangoproject.com/documentation/models/many_to_many ) Anda dapat menemukan beberapa contoh saat bekerja dengan ManytoMany Field, semoga ini dapat membantu Anda, jika jawaban saya bukan :)
mouad
1
aww .. maaf solusi kedua anda bekerja dengan baik :) Ada sedikit miss konfigurasi di pihak saya. Terima kasih teman-teman ini menyelamatkan hari saya ;-)
Grave_Jumper
19

Pendekatan paling sederhana untuk mencapai ini adalah memeriksa persamaan di seluruh instance (bukan id) di ManyToManyField. Itu terlihat jika instance berada di dalam hubungan banyak ke banyak. Contoh:

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

Saya tahu ini adalah pertanyaan lama, tapi sepertinya OP tidak pernah mendapatkan jawaban yang dia cari. Jika Anda memiliki dua set ManyToManyFields yang ingin Anda bandingkan, triknya adalah menggunakan __inoperatornya, bukan contains. Jadi misalnya jika Anda memiliki model "Peristiwa" dengan bidang ManyToMany ke "Grup" eventgroups, dan model Pengguna Anda (jelas) melampirkan ke Grup, Anda dapat membuat kueri seperti ini:

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

shacker
sumber
4

singularitas hampir benar dengan contoh pertama. Anda hanya perlu memastikan bahwa itu adalah daftar. Contoh kedua, memeriksa trigger_roles__id__exactadalah solusi yang lebih baik.

module.workflow_set.filter(trigger_roles__in=[self.role.id],allowed=True)
Josh Smeaton
sumber