Tricky Django GenericRelation Request

Suppose I have several models representing objects of real life: "Man", "Chair", "Room"

I also have a Collection model, which is a collection of records from these models.

Each model can be a member more than in the collection, so I also created the Membership model, which represents the object, is a member of the collection. It is defined as follows:

class Membership(models.Model):
   content_type   = models.ForeignKey(ContentType)
   object_id      = models.PositiveIntegerField()
   content_object = generic.GenericForeignKey('content_type', 'object_id')

   collection     = models.ForeignKey('Collection', related_name="members")

I want to create a QuerySet that provides a collection that represents all of its members in this model. I know that I can do this programmatically, but I need it in a QuerySet, which can be filtered, ordered, etc.

EDIT:

Obviously, this can be done using raw SQL:

   SELECT * FROM 
       ( modelx INNER JOIN membership ON modelx.id = membership.object_id) 
   WHERE 
       ( membership.collection_id=<my-collection-id> AND    
         membership.content_type_id=<modelx-type-id> )

But can it be represented using the Django query language?

+2
source share
3 answers

I seem to have found a solution using the method QuerySet extra:

def members_of_model(collection,cls):
    cls_type = ContentType.objects.get_for_model(cls)
    cm_tablename = CollectionMembership._meta.db_table
    cls_tablename = cls._meta.db_table
    return cls.objects.all().extra(tables=[cm_tablename],
                                   where=[ '%s.content_type_id=%%s' % cm_tablename,
                                           '%s.collection_id=%%s' % cm_tablename,
                                           '%s.object_id=%s.id' % (cm_tablename, cls_tablename) ],
                                   params=[cls_type.id,collection.id] )

Returns a valid QuerySet of a specific model that contains all the records that are members of a specific collection.

+2
source

I implemented exactly this using the method with_modelfor the custom manager for the membership model:

class CollectionMemberManager(models.Manager):
    use_for_related_fields = True

    def with_model(self, model):
        return model._default_manager.filter(pk__in=self.filter(member_content_type=ContentType.objects.get_for_model(model)).values_list('member_object_id', flat=True))

CollectionMemberis my equivalent to your model Membership. See the complete code for more details .

+1
source

No, It is Immpossible. Querysets can only be one type of model. Thus, you can get a set of requests for objects Membershipand refer to each property content_objectthat a related object will provide you with, but you cannot get all related objects directly in one set of requests.

0
source

All Articles