【问题标题】:Generic one-to-one relation in DjangoDjango中的通用一对一关系
【发布时间】:2011-12-11 20:19:51
【问题描述】:

我需要建立一对一的关系,它也必须是通用的。也许你可以给我一个更好的设计建议。到目前为止,我想出了以下模型

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 Admin 中,我想收集所有操作,然后我想从那里转到管理页面进行操作。是否可以避免在动作模型中创建 event 属性?有更好的解决方案吗?最好将字段events 和属性event 组合在一个定义中。我正在使用的项目使用 Django 1.1

【问题讨论】:

  • 如果你真的想避免events,你需要手动实现对Event表的查询,如下所示。我仍然更喜欢将 events 作为 GenericRelation,然后在 event 属性中使用 self.events.first()。此外,这将使您将来更容易删除唯一约束。

标签: python django django-models django-admin one-to-one


【解决方案1】:

我最近came across this problem。你所做的很好,但你可以通过创建一个透明地反转关系的 mixin 来进一步概括它:

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

您可能还想为反向关系添加缓存

【讨论】:

  • 它运作良好,但它没有能力这样做:Action.objects.select_related('event')
  • 我不喜欢这个解决方案 -> GenericRelation 看起来好多了,即使你需要使用 self.events.get()self.events.first()
  • 同上面的cmets。你最初使用GenericRelation 的效果要好得多。
【解决方案2】:

如果对象不存在则使用.get() return raise,如果对象不存在则.first() return None。

命名events_relation 是区分eventevents 的一种优雅方式。

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()

【讨论】:

  • 这是完整的解决方案
猜你喜欢
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多