Generic one-to-one relation in Django

I recently came across this problem. What you have done is fine, but you can generalise it a little bit more by creating a mixin that reverses the relationship transparently:

class Event(models.Model):
    content_type      = models.ForeignKey(ContentType)
    object_id         = models.PositiveIntegerField()
    content_object    = generic.GenericForeignKey('content_type', 'object_id')

    class Meta:
        unique_together   = ('content_type', 'object_id')

class EventMixin(object):
     @property
     def get_event(self):
         ctype = ContentType.objects.get_for_model(self.__class__)
         try:
             event = Event.objects.get(content_type__pk = ctype.id, object_id=self.id)
         except:
            return None 
         return event

class Action1(EventMixin, models.Model):
    # Don't need to mess up the models fields (make sure the mixing it placed before models.Model)
    ...

and

action = Action1.object.get(id=1)
event = action.get_event

You might want to add caching to the reverse relationship too


GenericRelation is a class for representing a Generic Many to One and adding a first_event property allow to represent a Generic One to One.

class Event(models.Model):
    content_type      = models.ForeignKey(ContentType)
    object_id         = models.PositiveIntegerField()
    content_object    = generic.GenericForeignKey('content_type', 'object_id')

    class Meta:
        unique_together   = ('content_type', 'object_id') # Important

class Action1(models.Model):
    events = generic.GenericRelation(Event)

    @property
    def first_event(self):
        return self.events.first()

In addition, I recommend using .first() inside Action1.first_event instead of .get() due to, it returning None if the event doesn't exist. .get() raises an exception if the event doesn't exist and this behavior can be unwanted.