Наследование Django ORM с полем ManyToMany - PullRequest
4 голосов
/ 10 ноября 2010

Допустим, у меня есть следующие классы ORM (поля для упрощения удалены):

class Animal(models.Model):
    say = "?"

    def say_something(self):
        return self.say

class Cat(Animal):
    self.say = "I'm a cat: miaow"

class Dog(Animal):
    self.say = "I'm a dog: wuff"

class Animals(models.Model):
    my_zoo = models.ManyToManyField("Animal")

Когда я добавляю животных в свой зоопарк:

cat = Cat()
cat.save()
dog = Dog()
dog.save()

animals.my_zoo.add(cat)
animals.my_zoo.add(dog)

for animal in animals.my_zoo.all():
    print animal.say_something()

... Я ожидаюследующий результат:

Я кот: мяу, я собака: ваф

но вместо этого все, что у меня есть, это экземпляры общего объекта Animal, неспособного что-либо сказать.но "?".

Как добиться истинного наследования объекта и последующего полиморфизма, когда объект извлекается из db?

Ответы [ 2 ]

4 голосов
/ 10 ноября 2010

Наследование модели в django не добавляет никакой информации о типе в базовый класс.Таким образом, на самом деле невозможно преобразовать объекты вниз из Animal () в соответствующие им формы.

Наследование используется только для отображения полей в унаследованной модели обратно в родительские модели.Таким образом, если в Animal есть поле name, то же поле будет существовать в Cat, а при сохранении Cat будет обновлено animal.

Наследование работает путем добавления отношения OneToOne:

class Animal(Model):
    name = CharField()

class Cat(Model):
    animal_ptr = OneToOneField(Animal)

Cat(name='Murky').save()

print repr(list(Animals.objects.all()))

: [Animal(name='Murky')]

Технически в вашей ситуации для Animal () даже возможно быть одновременно Dog () и Cat ():

animal = Animal()
animal.save()

Cat(animal_ptr=animal).save()
Dog(animal_ptr=animal).save()

Способ решения вашей проблемы будетдобавить поле subtype или аналогичное вашему Animal() объекту и реализовать функцию понижения рейтинга:

class Animal(Model):
    subtype = CharField()

    def downcast(self):
        if self.subtype == 'cat':
            return self.cat
            # The self.cat is a automatic reverse reference created
            # from OneToOne field with the name of the model

for animal in Animal.objects.all().select_related('dog', 'cat', ...)]:
    animal.downcast().say_something()

Несколько полезных операций чтения при переполнении стека с похожими темами: Универсальное множество-ко-многимотношения он капот. Как моделировать наследование в реляционных базах данных?

0 голосов
/ 10 ноября 2010

Вы можете получить доступ к потомкам через атрибут в родительском классе . Имя атрибута - это строчная версия названия модели:

class Animal(models.Model):
    say = "?"

    def say_something(self):
        for animal in ('cat', 'dog'):
            try:
                return getattr(self, animal).say
            except:
                pass
            return self.say
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...