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 eventclass 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
Use .get()
return raise if object doesn't exist, .first()
return None if object doesn't exist.
Name events_relation
is an elegant way to differentiate event
from events
.
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') # Importantclass Action1(models.Model): events_relation = generic.GenericRelation(Event) @property def event(self): # Return the object in exists # else None return self.events_relation.first()