How to get user by content_type ID

320 views Asked by At

I'm trying to use a django app that uses generic relations, and I'm new to content types. Using the admin, I can see an object that the user content type is 14

Therefore, I can write in a view

list = Action.objects.filter(actor_content_type=14)

And this produces a list of all the objects that match the user object

However, if I want a specific user, such as request.user, how would I filter for that? I have tried the following and failed

list = Action.objects.filter(actor_content_type=request.user)

Here is the Action model:

class Action(models.Model)
    user_content_type = models.ForeignKey(ContentType, related_name='actor')
    actor_object_id = models.CharField(max_length=255)
    actor = generic.GenericForeignKey('actor_content_type', 'actor_object_id')
1

There are 1 answers

0
kanu On

The ContentTypeManager has some methods for getting a content type.

ContentType.objects.get_for_model(model_or_instance)

ContentType.objects.get_by_natural_key(app_label, model)

Both methods use the same internal cache for their results. So using them instead of filtering directly may avoid hitting the database.

However if you only need the content type as a subquery you should filter like: (assuming your field name is 'actor_content_type')

Action.objects.filter(actor_content_type__app_label="auth",
        actor_content_type__model="user", actor_object_id=request.user.id)

or

Action.objects.filter(actor_content=ContentType.objects.filter(app_label="auth", 
        model="user"), actor_object_id=request.user.id)

It is worth to mention that although there is a nested query in the latest snippet django converts this into a single sql statement.

If you are planing on using the actions actors, note that this will hit the database for every action in the query. You can avoid this by setting the actor manually.

user = request.user
actions = Action.objects.filter(
    actor_content_type__app_label="auth",
    actor_content_type__model="user", 
    actor_object_id=user.id)

actor_cache_key = Action.actor.cache_attr
for action in actions:
    setattr(action, actor_cache_key, user)

Additional notes:

  • The actor_object_id should by an PositiveIntegerField.
  • Consider using index_together = (('actor_content_type', 'actor_object_id'),) on your models meta class.