Opened 8 years ago

Last modified 4 years ago

#27149 closed New feature

Filtering with generic relation — at Version 1

Reported by: MikiSoft Owned by: nobody
Component: Database layer (models, ORM) Version:
Severity: Normal Keywords: Queryset SubQuery Exists
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by MikiSoft)

The following function is used for filtering by generic relation (and also by one column in the model where it is) which isn't natively supported by Django.

def generic_rel_filter(model, target, column, id):
    return model.objects.extra(where=['''
        {app_label}_{model}.id in (select object_id
        from {app_label}_{target}
        where content_type_id = (select id from django_content_type where model = '{model}')
            and {column} = {id})'''.format(app_label=os.path.basename(os.path.dirname(__file__)), model=model.__name__.lower(), target=target, column=column, id=id)])

Example: If I have Event and Like model, and the second one has generic relation to the first one (i.e. it has content_type, object_id and content_object fields), then if I want to get all events which current user liked, I would just make this call in a view: generic_rel_filter(Event, 'like', 'person', self.request.user.pk)

Note that this function isn't intended to be used with user specified parameters, otherwise it's prone to SQL injection attacks.

P.S. It can be done with ORM but then it would go with three queries, which is much slower than the method above (which uses only one query to do the same): Event.objects.filter(pk__in=Like.objects.filter(content_type=ContentType.objects.get(model='event'), person=self.request.user).values_list('object_id', flat=True))

Change History (1)

comment:1 by MikiSoft, 8 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top