使用Django继承区分父模型的子模型

1 投票
3 回答
1746 浏览
提问于 2025-04-15 18:54

基本上,我有一个叫“Program”的基础类。然后我有一些更具体的程序模型类型,它们都是以Program作为基础类。对于我99%的需求,我并不在乎一个Program是不是某个具体的子类型。当然,有1%的时候我确实想知道它是不是子类型之一。

问题是,如果我有一个叫SwimProgram的模型和一个叫CampProgram的模型,它们都是以Program为基础,那么在没有一堆try/except块的情况下,想要知道它们是什么类型就会很麻烦。我想要的东西大概是这样的:

program = models.Program.objects.get(id=15)
if program.swimprogram:
    ## do stuff
elif program.campprogram:
    ## do stuff
else:
    ## do other stuff

当然,这样会抛出DoesNotExist的异常。我可以使用try/except来处理,这样看起来不太美观,或者我可以让Program有一个'type'字段,让子类在保存时设置这个字段。这两种方法都可以,但我想知道有没有人有更好的办法。

3 个回答

0

// 更新

正如这篇帖子评论中提到的,我理解错了问题。下面的回答并不能解决这个问题。


嗨,f4nt,

我现在想到的最简单的方法是:

program = models.Program.objects.get(id=15)

if program.__class__.__name__ == 'ModelA':
  # to something

if program.__class__.__name__ == 'ModelB':
  # to something

为了让这个更好,你可以在基础模型里写一个方法:

class MyModel(models.Model):

  def instanceOfModel(self, model_name):
    return self.__class__.__name__ == model_name

这样,上面的代码看起来会是这样的:

program = models.Program.objects.get(id=15)

if program.instanceOfModel('ModelA'):
  # to something

if program.instanceOfModel('ModelB'):
  # to something

不过你可以想象,这样写起来不太美观。你可以看看内容类型框架,它可能会帮助你以更优雅的方式实现同样的功能。

希望这能帮到你!

1

几周前,有人在django-developers邮件列表上介绍了一个非常有趣的扩展,它可以让Django的ORM(对象关系映射)返回子类对象,而不是返回父类对象。你可以在这里详细了解:

http://bserve.webhop.org/wiki/django_polymorphic

我自己还没试过这个扩展(但肯定会试试),不过看起来它很适合你的需求。

4

你试过使用 hasattr() 吗?可以像这样做:

if hasattr(program, 'swimprogram'):
    # ...
elif hasattr(program, 'campprogram'):
    # ...

如果你对这种方法不太确定,建议先在一个简单的测试应用中试一下。这里有两个简单的模型,可以帮助你看看这个方法是否适合你,以及你正在使用的 Django 版本(在 django-1.1.1 中测试过)。

class Archive(models.Model):
    pub_date = models.DateField()

    def __unicode__(self):
        return "Archive: %s" % self.pub_date

class ArchiveB(Archive):
    def __unicode__(self):
        return "ArchiveB: %s" % self.pub_date

然后在命令行中试试:

> a_id = Archive.objects.create(pub_date="2010-10-10").id
> b_id = ArchiveB.objects.create(pub_date="2011-11-11").id
> a = Archive.objects.get(id=a_id)
> b = Archive.objects.get(id=b_id)
> (a, b) # they both look like archive objects
(<Archive: Archive: 2010-10-10>, <Archive: Archive: 2011-11-11>)
> hasattr(a, 'archiveb')
False
> hasattr(b, 'archiveb') # but only one has access to an ArchiveB
True

撰写回答