Django ORM:覆盖子类中Field的related_name

时间:2017-03-20 09:23:29

标签: django django-models

我得到了这个例外:

  

django.core.exceptions.FieldError:

     

本地字段'票据'在课堂上#SpecialPlugin'与基类' BasePlugin'

中的类似名称字段发生冲突

以下是我的模特:

class BasePlugin(models.Model):
    ticket = models.OneToOneField('foobar.ticket', primary_key=True, 
                                  related_name='%(app_label)s_%(class)s')

    class Meta(IndexImplementation.Meta):
        abstract = True

    # .. Other stuff which should be available for SpecialPlugin 
    #    and other child classes.

class SpecialPlugin(BasePlugin):
    ticket = models.OneToOneField('foobar.ticket', primary_key=True, 
                                  related_name='special')

我只有found this note,但在我的情况下,父类是抽象的。我不确定它是否适用于此。

我想给孩子班SpecialPlugin提供相关名称" special"因为BasePlugin的相关名称(%(app_label)s_%(class)s)会破坏旧代码。

有没有办法给SpecialPlugin.ticket提供related_name" special"?

3 个答案:

答案 0 :(得分:10)

更新

使用django的default_related_name元选项可以完成类似的事情。

它可能看起来像一个丑陋的黑客,但你可以设置一个函数调用related_name参数而不是字符串。然后在子类/模型中覆盖该函数。

class BasePlugin(models.Model):

    @staticmethod
    def get_ticket_related_name():
        return '%(app_label)s_%(class)s'

    ticket = models.OneToOneField('foobar.ticket', primary_key=True, 
                                  related_name=get_ticket_related_name.__func__())

    class Meta(IndexImplementation.Meta):
        abstract = True


class SpecialPlugin(BasePlugin):
    @staticmethod
    def get_ticket_related_name():
        return 'special'

答案 1 :(得分:0)

看起来问题的核心在于覆盖模型字段Django model inheritance, overriding fields

对您来说,简单的解决方法是将BasePlugin解耦为没有ticket字段的类,然后创建一个包含ticket字段的子类

class BaseWithoutTicketPlugin(models.Model):
    # .. Other stuff which should be available for SpecialPlugin 
    #    and other child classes.
    class Meta(IndexImplementation.Meta):
        abstract = True

class BasePlugin(BaseWithoutTicketPlugin):
    ticket = models.OneToOneField('foobar.ticket', primary_key=True, 
                                  related_name='%(app_label)s_%(class)s')

    class Meta(BaseWithoutTicketPlugin.Meta):
        abstract = True


class SpecialPlugin(BaseWithoutTicketPlugin):
    ticket = models.OneToOneField('foobar.ticket', primary_key=True, 
                                  related_name='special')

想法是在您需要自定义BaseWithoutTicketPlugin时使用ticket,并在您不需要时使用BasePlugin

答案 2 :(得分:0)

在 Meta 类中使用默认相关名称:

class SpecialPlugin(BasePlugin):
    class Meta:
        default_related_name = 'special_plugins'