Search code examples
djangodjango-admin

Error: 'EventsRaw' has no ForeignKey to 'UserEvents' - Reverse-Related GenericForeignKey Inline Form in Django Admin


I'm encountering an error while attempting to add a reverse-related GenericForeignKey inline form to a model in Django admin. The specific error message states: "'EventsRaw' has no ForeignKey to 'UserEvents'."

Here's what I need assistance with:

  1. Displaying UserEvents in the Django admin dashboard.
  2. When navigating to the UserEvents page in the admin dashboard, I would like to see a list of all EventsRaw objects that are reverse-related.

Thank you in advance for your help!

# models.py
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType


class UserEvents(models.Model):
    content_type = models.ForeignKey(
        ContentType, on_delete=models.CASCADE, null=True, blank=True
    )
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey("content_type", "object_id")


class EventsRaw(models.Model):
    raw_message = models.JSONField()


# For Creating test data
def create_events_raw():
    events_raw = EventsRaw()
    events_raw.raw_message = "test"
    events_raw.save()

    user_event = UserEvents()
    user_event.content_object = events_raw
    user_event.save()
# admin.py
from django.contrib import admin
from .models import UserEvents, EventsRaw


class EventsRawInline(admin.TabularInline):
    model = EventsRaw


@admin.register(UserEvents)
class User_EventsAdmin(admin.ModelAdmin):
    inlines = (EventsRawInline,)


Solution

  • You can add a GenericRelation [Django-doc] in reverse, so:

    from django.contrib.contenttypes.fields import GenericRelation
    
    
    class EventsRaw(models.Model):
        raw_message = models.JSONField()
        user_event = GenericRelation(UserEvents)

    As for the admin, you can work with a GenericTabularInline [Django-doc] over a TabularInline:

    from django.contrib.contenttypes.admin import GenericTabularInline
    
    
    class EventsRawInline(GenericTabularInline):
        model = EventsRaw

    This will then produce a query with the content type filled in. But while GenericForeignKeys are indeed possible, they often will introduce a new level of complexity, and therefore are often not a good idea.


    Note: normally a Django model is given a singular name, so UserEvent instead of UserEvents.