Определить дочерний тип с помощью Django MTI или указать тип в качестве поля? - PullRequest
2 голосов
/ 21 октября 2010

Я настраиваю модель данных в django, используя наследование нескольких таблиц (MTI), например:

class Metric(models.Model):
    account = models.ForeignKey(Account)
    date = models.DateField()
    value = models.FloatField()
    calculation_in_progress = models.BooleanField()
    type = models.CharField( max_length=20, choices= METRIC_TYPES ) # Appropriate?

    def calculate(self):
        # default calculation...

class WebMetric(Metric):
    url = models.URLField()

    def calculate(self):
        # web-specific calculation...

class TextMetric(Metric):
    text = models.TextField()

    def calculate(self):
        # text-specific calculation...

Мой инстинкт состоит в том, чтобы поместить поле 'type' в базовый класс, как показано здесь, чтобы я мог сказать, какому подклассу принадлежит любой объект Metric. Было бы немного хлопотно постоянно обновлять информацию, но это возможно. Но мне нужно сделать это? Есть ли способ, которым django обрабатывает это автоматически?

Когда я вызываю Metric.objects.all(), каждый возвращаемый объект является экземпляром Metric, а не подклассами. Поэтому, если я позвоню .calculate(), я никогда не пойму поведение подкласса.

Я мог бы написать функцию в базовом классе, которая проверяет, могу ли я привести ее к любому из подтипов, таких как:

def determine_subtype(self):
    try:
        self.webmetric
        return WebMetric
    except WebMetric.DoesNotExist:
        pass
    # Repeat for every sub-class

но это похоже на кучу повторяющегося кода. И это также не то, что может быть включено в фильтр SELECT - работает только в пространстве Python.

Какой лучший способ справиться с этим?

Ответы [ 2 ]

1 голос
/ 25 октября 2010

Несмотря на то, что это может нарушить восприимчивость некоторых людей, единственный практический способ решить эту проблему - поместить поле или метод в базовый класс, который сообщает, какой тип объекта представляет каждая запись.Проблема описанного вами метода заключается в том, что он требует отдельного запроса к базе данных для каждого типа подкласса, для каждого объекта, с которым вы имеете дело.Это может быть очень медленным при работе с большими наборами запросов.Лучшим способом является использование ForeignKey для класса типов контента django.

@ Карл Мейер написал хорошее решение здесь: Как получить доступ к дочерним классам объекта в django, не зная именидочерний класс?

Одиночное наследование таблиц может помочь решить эту проблему, в зависимости от того, как она реализована.Но на данный момент Django не поддерживает его: Наследование одной таблицы в Django , так что это бесполезное предложение.

0 голосов
/ 21 октября 2010

Но нужно ли это делать?

Никогда.Никогда.Никогда.

Есть ли способ, которым django обрабатывает это автоматически?

Да.Это называется «полиморфизм».

Вам никогда не нужно знать подкласс.Никогда.

"А как насчет моих атрибутов WebMetric.url и My TextMetric.text?"

Что вы будете делать с этими атрибутами?Определите функцию метода, которая делает что-то.Реализуйте разные версии в WebMetric (который использует url) и TextMetric (который использует текст).Это правильный полиморфизм.


Пожалуйста, прочитайте это: http://docs.djangoproject.com/en/1.2/topics/db/models/#abstract-base-classes

Пожалуйста, сделайте ваш суперкласс абстрактным.

НЕ делайте этого: http://docs.djangoproject.com/en/1.2/topics/db/models/#multi-table-inheritance

Требуется «наследование одной таблицы».

...