I need to set up one-to-one relation which must also be generic. May be you can advice me a better design. So far I came up to the following models
class Event(models.Model): # skip event related fields... 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 Action1(models.Model): # skip action1 related fields... events = generic.GenericRelation(Event, content_type_field='content_type', object_id_field='object_id') @property def event(self): return self.events.get() # <<<<<< Is this reasonable? class Action2(models.Model):...
In Django Admin in event list I want to collect all actions, and from there I want go to admin pages for actions. Is it possible to avoid creating event
property in the action models? Is there a better solution? It would be nice to combine the field events
and the property event
in a single definition. The project I am working with uses Django 1.1
Generic relations. Adding a foreign key from one of your own models to ContentType allows your model to effectively tie itself to another model class, as in the example of the Permission model above.
One-to-one fields:This is used when one record of a model A is related to exactly one record of another model B. This field can be useful as a primary key of an object if that object extends another object in some way. For example – a model Car has one-to-one relationship with a model Vehicle, i.e. a car is a vehicle.
To handle One-To-Many relationships in Django you need to use ForeignKey . The current structure in your example allows each Dude to have one number, and each number to belong to multiple Dudes (same with Business).
Content types are Django's way of identifying database tables. Every Database table is represented as a row in the content type table which is created and maintained by 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
Using the name events_relation
for the GenericRelation inside the 'Action1' class is an elegant way to clearly differentiate event
from events
.
Inside Action1.event
I recommend using .first()
due to it returning None if the object doesn't exist. .get()
raises an exception if the object doesn't exist and this behavior can be unwanted.
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_relation = generic.GenericRelation(Event) @property def event(self): # Return the object in exists # else None return self.events_relation.first()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With