Search code examples
djangodjango-querysetdjango-contenttypes

Using Django LogEntry (ContentType) with a GenericRelation field


THE DESCRIPTION

I'm writing an API on a Django project that will get all the LogEntry on a specific model and filter them by the specific model's field. So my model looks like this:

from django.contrib.admin.models import ContentType, LogEntry
from django.contrib.auth.models import Group
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.db import models


class LogEntryProxy(LogEntry):
    content_object = GenericForeignKey()

    class Meta:
        proxy = True


class HomeItem(models.Model):
    # Some Fields
    groups = models.ManyToManyField(Group, related_name="home_item_group")
    log_entry_relation = GenericRelation(LogEntryProxy, related_query_name='log_homeitem')

In the view I need to be able to make queries that fetch LogEntryProxy items that refer to HomeItem and filter them by the groups that have access to it and serialize the results. so something like this:

log_entry_queryset = LogEntryProxy.objects.filter(log_homeitem__groups__in=user.groups.all()).distinct()

My serializer looks like this (using "djangorestframework"):

from rest_framework import serializers


class LogEntryHomeItemSerializer(serializers.ModelSerializer):
    content_object = HomeItemSerializer(many=False)
    object_id = serializers.IntegerField()

    class Meta:
        model = LogEntryProxy
        fields = ('object_id', 'action_flag', 'content_object', )

And it works!

THE PROBLEM

So what's the problem you may ask!

The Problem is that LogEntry actions like create and edit work! and the API will give you the results, but when you delete a HomeItem object all the LogEntry objects pointing to it will be deleted as well, thus no delete action will be given by the api (plus all the create and edit ones pointing to that object will be deleted as well). and that's all because Django's GenericRelation doesn't support on_delete. If I delete the GenericRelatin field this doesn't happen but then I have to be able to filter the HomeItem by groups in the LogEntryProxy queryset and it can't be done without the GenericRelation.

I was wondering if anyone could tell me what to do in this situation?

Should I implement a custom logging system? or there's another way that I haven't seen it yet!


Solution

  • try:

    homeids = HomeItem.objects.filter(groups__in=user.groups.all()).values_list('id',flat=True)
    log_entry_queryset = LogEntryProxy.objects.filter(object_id__in=homeids,content_type_id=ContentType.objects.get_for_model(HomeItem).id).distinct()
    

    If you query this way you don't need GenericRelation

    Update: The above query will not fetch logentries of delete action. It can be done like:

    from django.db.models import Q 
    from django.contrib.admin.models import DELETION 
    log_entry_queryset = LogEntryProxy.objects.filter(Q(object_id__in=home_ids,content_type_id=ContentType.objects.get_for_model(HomeItem).id) | Q(action_flag=DELETION,content_type_id=ContentType.objects.get_for_model(HomeItem).id)).distinct()