views:

52

answers:

2

Hi,

I have 3 Models, the TaggedObject has a GenericRelation with the ObjectTagBridge. And the ObjectTagBridge has a ForeignKey to 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 am attaching a Tag to an Object, I am creating a new ObjectTagBridge and set its ForeignKey tag to the Tag I want to attach. That is working fine, and I can get all Tags that I attached to my Object very easy. But when I want to get (filter) all Objects that have Tag1 and Tag2 I tried to 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 2 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. In fact any combination of binary conjunctions, like: (...) and ( (...) or not(...))

How can I filter this correctly? Every answer is welcome, maybe there is also a different way do achieve this.

thx for your help!!!

A: 

It looks like you are trying to manually implement a Many-to-Many table and then combine that with a generic relation. A better approach might be to let Django handle the M2M for you, and just have it represented on the generic relationship like so:

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 should let you do what you were trying to do...

objects = TaggedObject.objects.filter(
    Q(tags=Tag1) & Q(tags=Tag2)
)
T. Stone
thx. but in my case i need also to attach additional information to the tag <-> object relation so i need the extra table. Another advantage of this approach is, that i can create multiple classes, that inherit from TaggedObject, and from the view from the Tag it is no difference which Object is tagged.
HWM-Rocker
A: 

If the result you are looking for is a TaggedObject with Tag1 and Tag2, consider querying the TaggedObject instead of querying the ObjectTagBridge. This is what that query might look like:

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

Essentially we are conducting two filters. Only objects with both Tag1 and Tag2 will pass the filtering criteria and be a part of the result set.

Mathieu Steele
yeah, you are right. I hoped to that I could do that with the Q object. In that case I could use the same filter for different TaggedObjects. I rewrote my API and implemented it in that way. THX
HWM-Rocker