Различение детей родительской модели с наследованием Джанго

В основном у меня есть Базовый класс, который называется "Программа". Затем у меня есть более конкретные типы моделей программ, которые используют Программу в качестве базового класса. Что касается 99% моих потребностей, мне все равно, является ли Программа одним из конкретных типов детей. Конечно, есть 1% времени, когда я хочу знать, является ли это один из детей.

Проблема заключается в том, что если у меня есть, скажем, модель SwimProgram и модель CampProgram, использующая в качестве базы Program, то проблематично выяснить, что это такое, без множества блоков try/ кроме. Я хочу что-то вроде следующего:

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

Конечно, это приводит к исключениям типа DidNotExist. Я мог бы использовать try/excepts, которые являются более уродливыми, или у меня могла бы быть программа, имеющая поле 'type', которое дети сохраняли при сохранении. И то и другое выполнимо, но мне любопытно, есть ли у кого-нибудь лучшие методы.

3 ответа

Решение

Вы пробовали 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

Пару недель назад кто-то из списка рассылки django-developers представил очень интересное расширение ORM в Django, которое заставляет QuerySets возвращать подклассовые объекты вместо объектов родительского класса. Вы можете прочитать все об этом здесь:

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

Я сам еще не пробовал (но, безусловно, буду), но, похоже, подходит для вашего случая использования.

// Обновить

Как указано в комментариях к этому посту, я неправильно понял вопрос. Ответ ниже не решит проблему.


Привет 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

Но, как вы можете себе представить, это ужасно. Вы можете посмотреть на структуру типов контента, которая может помочь вам сделать то же самое, за исключением более элегантного.

Надеюсь, это поможет!

Другие вопросы по тегам