Django中的通用一对一关系
我需要建立一个一对一的关系,而且这个关系还得是通用的。也许你能给我一些更好的设计建议。目前我想到的模型如下:
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):...
在Django的管理界面中,我想在事件列表里收集所有的操作,然后从那里跳转到操作的管理页面。有没有办法避免在操作模型中创建event
这个属性?有没有更好的解决方案?如果能把events
这个字段和event
这个属性合并成一个定义就太好了。我现在正在做的项目使用的是Django 1.1。
2 个回答
11
GenericRelation
是一个用来表示通用的多对一关系的类,添加一个 first_event
属性可以用来表示通用的一对一关系。
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()
另外,我建议在 Action1.first_event
中使用 .first()
方法,而不是 .get()
。因为如果事件不存在,.first()
会返回 None
,而 .get()
如果找不到事件就会抛出一个异常,这种情况可能会让人不太想要。
21
我最近遇到了一个问题,具体可以查看这个链接。你所做的事情是没问题的,但你可以通过创建一个混合类来让这个关系反转得更通用一些,这样做会更方便:
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)
...
还有
action = Action1.object.get(id=1)
event = action.get_event
你可能也想给反转的关系加上缓存,这样会更高效。