2010-12-22 62 views
49

Estoy tratando de filtrar un montón de objetos a través de una relación muchos a muchos. Como el campo trigger_roles puede contener múltiples entradas, probé el filtro contiene. Pero como eso está diseñado para ser usado con cadenas, estoy bastante indefenso sobre cómo debería filtrar esta relación (puede ignorar la lista values_list() atm).Django filter many-to-many with contains

Esta función está unida al perfil de usuario:

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) 

Mi modelo de flujo de trabajo se parece a esto (simplificado):

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) 

Aunque la solución podría estar en silencio simple, mi cerebro no lo hará Dime.

Gracias por su ayuda.

Respuesta

66

Ha intentado algo como esto:

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

o simplemente si self.role.id no es una lista de PKS:

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

Eso no lo hace parece que funciona Como self.role.id es solo una int y la trigger_roles es una lista de ellas, necesitaría una entrada invertida, como contiene, pero como he descubierto, contiene solo para cadenas. –

+5

El segundo ejemplo * debería * funcionar. Si el valor en 'self.role.id' es uno de los roles desencadenantes, ese filtro debe extraer todos los flujos de trabajo donde uno de los roles de desencadenante es el valor en' self.role.id'. Básicamente, esto se comportará exactamente como una función "contiene". A menos que nos estemos perdiendo algo. –

+0

@Jordan Reiter: "contiene" se convierte en sql a "me gusta", que no es lo que quiere el OP y creo que ya lo señala, en cambio, "exacto" se convierte en "=" o "es", que es la idea aquí. – mouad

4

singularidad es casi justo con el primer ejemplo. Solo necesitas asegurarte de que sea una lista. El segundo ejemplo, verificar trigger_roles__id__exact es una mejor solución.

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

El método más sencillo para lograr esto sería el registro de equalty sobre toda la instancia (en lugar del ID) en el ManyToManyField. Eso se ve si la instancia está dentro de la relación de muchos a muchos. Ejemplo:

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

Sé que esta es una vieja pregunta, pero parece que el OP nunca obtuvo la respuesta que estaba buscando. Si tiene dos conjuntos de ManyToManyFields que desea comparar, el truco es usar el operador __in, no contains. Así, por ejemplo, si tiene un modelo de "evento" con un ManyToMany al "grupo" en el campo eventgroups, y su modelo de usuario (obviamente) se une al grupo, puede consultar la siguiente manera:

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

Cuestiones relacionadas