2017-03-20 59 views
3

我得到这个异常:Django的ORM:在子类领域的覆盖related_name

django.core.exceptions.FieldError:

Local field 'ticket' in class 'SpecialPlugin' clashes with field of similar name from base class '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,但在我的情况下,父亲是一个抽象类。我不确定它是否适用于此。

因为BasePlugin的相关名称(%(app_label)s_%(class)s)会破坏旧代码,所以我想给子类SpecialPlugin添加相关名称“special”。

有没有办法给SpecialPlugin.ticket related_name“special”?

+0

此错误应该只会出现,如果父类是**不是**抽象。我刚刚用简单的模型进行了测试,类似于你的模型,并且工作正常。如果您查看引发异常的Django代码,它会检查父类是否为抽象类。这暗示了'BasePlugin'不正确地被设置为抽象。 “IndexImplementation.Meta”中有什么? – solarissmoke

+0

@solarissmoke IndexImplementation.Meta是abstract = True。这就是为什么我不明白错误信息。 – guettli

回答

3

它可能看起来像一个丑陋的黑客,但你可以设置一个函数调用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' 
+0

这个答案看起来不错 – guettli

+1

我的子类中的get_ticket_related_name永远不会被调用 – kzh

+0

@kzh你确定:1.你的基类是抽象的2.改变子类中get_ticket_related_name方法的外观/声明顺序修复它? – v1k45

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

想法是,当你需要定制ticket和使用BasePlugin当你不使用BaseWithoutTicketPlugin

+0

BasePlugin具有其他需要的属性。我需要从它继承。对不起,我正在剥离我的代码来解决这个问题......也许很多人被剥夺了。我更新了这个问题。 – guettli

+0

@guettli仍然没有看到我的建议中的问题,我更新了我的答案。 –

+0

“其他东西”部分需要属性“ticket”。这意味着您需要将此部分移至“BasePlugin”。在做完这些之后,其他东西部分不再用于SpecialPlugin :-( – guettli