How to properly filter Many2Many / Generic Relations with Q?

I have 3 models, TaggedObject has GenericRelation with ObjectTagBridge. And ObjectTagBridge has a ForeignKey for the tag model.

class TaggedObject(models.Model):
    """
        class that represent a tagged object
    """
    tags = generic.GenericRelation('ObjectTagBridge',
                                   blank=True, null=True)

class ObjectTagBridge(models.Model):
    """
        Help to connect a generic object to a Tag.
    """
    # pylint: disable-msg=W0232,R0903
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    tag = models.ForeignKey('Tag')

class Tag(models.Model):
    ...

      

when I attach a tag to an object, I create a new ObjectTagBridge and set its ForeignKey tag to the tag I want to attach. This works fine and I can get all the tags that I have attached to the object very easily. But when I want to get (filter) all objects that have Tag1 and Tag2, I tried to do something like this:

query = Q(tags__tag=Tag1) & Q(tags__tag=Tag2)
object_list = TaggedObjects.filter(query)

      

but now my object_list is empty because it is looking for TaggedObjects that have one ObjectTagBridge with two tag objects, the first with Tag1 and the second with Tag2.

I my application will be more complex Q-queries than this one, so I think I need a solution with this Q object. Actually any combination of binary conjunctions like: (...) and ( (...) or not(...))

How can I filter this correctly? Each answer is appreciated, there may be another way to achieve this.

thanks for your help!!!

+2


a source to share


2 answers


If the result you are looking for is a TaggedObject with Tag1 and Tag2, consider a TaggedObject request instead of an ObjectTagBridge request. This is what this request looks like:

results = TaggedObject.objects.filter(objecttagbridge__tag = Tag1).filter(objecttagbridge__tag = Tag2)

      



Essentially, we are running two filters. Only objects with Tag1 and Tag2 will pass filter criteria and be part of the result set.

+1


a source


It looks like you are trying to manually implement a Many-to-Many table and then join it with a generic relationship. A better approach might be to let Django handle M2M for you, and simply represent it in general terms like this:

class TaggedObject(models.Model):
    """
        Help to connect a generic object to a Tag.
    """
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    tags = models.ManyToManyField('Tag')

class Tag(models.Model):
    ...

      



This will allow you to do what you were trying to do ...

objects = TaggedObject.objects.filter(
    Q(tags=Tag1) & Q(tags=Tag2)
)

      

0


a source







All Articles