Suppose I have a few models representing real life objects: "Person", "Chair", "Room"
I also have a "Collection" model, which represents some collection of records of these models.
Each model can be a member of more than on collection - therefore, I have also created a "Membership" model, which represents an object is a member of a collection. It is defined as follows:
c开发者_StackOverflow社区lass 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 be able to create a QuerySet, which given a collection, represents all its members of a given model. I know I can do it 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?
It seems I have found the solution, by using QuerySet's extra method:
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] )
This returns a valid QuerySet of a specific model, which holds all records which are members of a specific collection.
I implemented exactly this by way of a with_model method on a 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))
CollectionMember is my equivalent to your Membership model. For more context, see the code in its entirety.
No, this isn't possible. Querysets can only ever be of one single model type. So you can get a queryset of Membership objects and refer to each one's content_object property, which will give you the related object, but you can't get all the related objects directly in one queryset.
加载中,请稍侯......
精彩评论