Django管理界面不使用子类的__unicode __() [英] Django Admin Interface Does Not Use Subclass's __unicode__()

查看:130
本文介绍了Django管理界面不使用子类的__unicode __()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(Django 1.x,Python 2.6.x)



我有以下模式:

  class Animal(models.Model):
pass

class Cat(Animal):
def __unicode __(self):
返回这是一只猫

class Dog(Animal):
def __unicode __(self):
返回这是一只狗

class AnimalHome(models.Model):
animal = models.ForeignKey(Animal)

我没有实例化动物,因为这应该是一个虚拟类。我已经实例化了猫和狗,但在AnimalHome的管理页面中,我对动物的选择显示为动物对象(默认__unicode __(),我猜),而不是我为两个子类定义的__unicode__。帮助。






我认为抽象基类问题是一个红色的鲱鱼。即使Animal不是抽象的,我还是有一个问题,由于某些原因,由于ForeignKey被定义在Animal而不是其子类之中,所以超类方法被调用而不是子类。在OO编程中,当你调用object.method()时,你应该得到最低子类的实现,你必须做更多的工作来获得任何超类的实现。那么为什么在子类上定义__unicode__是不够的 - 实际上问题可能是__unicode__根本没有被调用,因为Animal类的内省表明它没有被定义。所以也许如果我定义__unicode__为动物,并让它调用子类__unicode__我可以得到所需的效果。






我认为我了解ORM的问题。这两个答案都帮我理解了,谢谢。在尝试这个时,我发现Django保存一个子类的模型时,它有两件事情:(1)它为超类的表中的子类对象创建一行,(2)它使子类表中的PK与在超类表中分配的PK。这个在子类表中的PK被命名为superclass_ptr。基于此,我制作了以下内容。我会很感激的反馈。

 类Animal(models.Model)
def __unicode __(self):
如果Dog.objects.filter(pk = self.pk).count()> 0:
return unicode(Dog.objects.get(pk = self.pk))
elif Cat.objects.filter(pk = self.pk).count()> 0:
return unicode(Cat.objects.get(pk = self.pk))
else:
返回An Animal!






似乎劳伦斯是最点的wrt这个问题。猫和狗将有不相交的PK集(动物的任何子类都将具有与其超类的记录相同的PK),但不幸的是Django在幕后不执行任何工作:我是动物,我知道动物有小猫和猫,具体来说,我是3号动物,而且我刚检查过,还有一个猫号3,这意味着我实际上是猫3号。即使这似乎是完全可能和非常合理的(因为猫不会做任何动物不能自己做)任何使用Python的内省。谢谢大家。

解决方案

ForeignKey(Animal)只是一个外键引用的动态表中的一行。底层SQL架构中没有任何表示该表被用作超类的内容,因此您可以返回一个Animal对象。



要解决此问题:



首先,你希望基类是非抽象的。这对于ForeignKey来说也是必要的,并且还可以确保Dog和Cat将具有分离的主键集。



现在,Django使用OneToOneField实现继承。因此,具有子类实例的基类的实例将获得对该实例的引用,这个实例名称适当。这意味着您可以执行以下操作:




def __unicode __(self):
if hasattr(self,'dog'):
return self $($)
elif hasattr(self,'cat'):
return self.cat .__ unicode __()
else:
return'Animal'

这也解决了您对Ber的一个 unicode ()的问题,这取决于其他子类属性。现在,您正在子类实例上调用适当的方法。



现在,这表明,由于Django已经在幕后寻找子类实例,因此代码可能只是一路走来,返回一只猫或狗的实例,而不是一只动物。你必须用开发者来处理这个问题。 :)


(Django 1.x, Python 2.6.x)

I have models to the tune of:

class Animal(models.Model):
  pass

class Cat(Animal):
  def __unicode__(self):
    return "This is a cat"

class Dog(Animal):
  def __unicode__(self):
    return "This is a dog"

class AnimalHome(models.Model):
  animal = models.ForeignKey(Animal)

I have instantiated no Animals, because this is supposed to be a virtual class. I have instantiated Cats and Dogs, but in the Admin Page for AnimalHome, my choices for Animals are displayed as "Animal object" (the default __unicode__(), I guess) as opposed to the __unicode__ I have defined for the two subclasses. Help.


The abstract base class issue is a red herring wrt to this question, I think. Even if Animal was not supposed to be abstract, I still have the problem that, for some reason, since the ForeignKey is defined on Animal and not one of its subclasses, the superclass method is being called instead of the subclass. In OO programming when you call object.method() you're supposed to get the lowest-subclass's implementation, and you have to do extra work to get any superclass's implementation. So why is it that having __unicode__ defined on the subclasses is not sufficient for --- actually the problem might be that __unicode__ is not getting called at all because introspection on the Animal class reveals that it's not defined. So maybe if I define __unicode__ for Animal and have it call subclasses' __unicode__ I could get the desired effect.


Okay, I think that I understand the ORM issues. Both these answers have helped me understand this, thank you. While experimenting with this, I discovered that when Django saves a subclassed model, it does two things: (1) it creates a row for the subclassed object in the superclass's table, and (2) it makes the PK in the subclass table identical to the PK assigned in the superclass table. This PK in the subclass table is named superclass_ptr. Based upon this I've concocted the following. I'd appreciate feedback.

Class Animal(models.Model)
  def __unicode__(self):
    if Dog.objects.filter(pk=self.pk).count() > 0:
      return unicode(Dog.objects.get(pk=self.pk))
    elif Cat.objects.filter(pk=self.pk).count() > 0:
      return unicode(Cat.objects.get(pk=self.pk))
    else:
      return "An Animal!"


It seems that Lawrence is most on-point wrt this question. Cat and Dog will have disjoint PK sets (and any subclass of Animal will have a PK identical to the record of its superclass), but unfortunately Django does not perform any work behind the scenes a la: "I'm an Animal. I know Animals have subclasses Dog and Cat. Specifically, I'm Animal number 3, and furthermore I just checked and there's a Cat number 3 too. That means that I'm actually Cat number 3". Even though this seems entirely possible and very reasonable (since a Cat won't do anything an Animal couldn't do itself) using Python's introspection. Thank you all.

解决方案

ForeignKey(Animal) is just that, a foreign key reference to a row in the Animal table. There's nothing in the underlying SQL schema that indicates that the table is being used as a superclass, so you get back an Animal object.

To work around this:

First, you want the base class to be non-abstract. This is necessary for the ForeignKey anyway, and also ensures that Dog and Cat will have disjunct primary key sets.

Now, Django implements inheritance using a OneToOneField. Because of this, an instance of a base class that has a subclass instance gets a reference to that instance, named appropriately. This means you can do:

class Animal(models.Model):
    def __unicode__(self):
        if hasattr(self, 'dog'):
            return self.dog.__unicode__()
        elif hasattr(self, 'cat'):
            return self.cat.__unicode__()
        else:
            return 'Animal'

This also answers your question to Ber about a unicode() that's dependent on other subclass attributes. You're actually calling the appropriate method on the subclass instance now.

Now, this does suggest that, since Django's already looking for subclass instances behind the scenes, the code could just go all the way and return a Cat or Dog instance instead of an Animal. You'll have to take up that question with the devs. :)

这篇关于Django管理界面不使用子类的__unicode __()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆