2013-10-02 7 views
0

У меня есть абстрактный объект, называемый параметром. параметр может иметь несколько разных типов. Например - числовой параметр, параметр константы, параметр MultiValue и т. Д. Каждый параметр может быть связан со многими параметрами разных типов и наоборот.От многих до многих отношений с наследованием модели в Django

После рассмотрения документа Django на Model inheritance Я решил, что мне нужен простой abstract base class. Пример отношения многих к многим из базового класса можно найти позже в документах.

class ParameterBase(models.Model): 
    id = models.AutoField(primary_key=True)  
    description = models.CharField(max_length=200) 
    sort_order = models.DecimalField(null=False, max_digits=6, decimal_places=4) 

    m2m = models.ManyToManyField('self',related_name='dependent_on') 

    class Meta: 
     abstract = True 

class ParameterConstant(ParameterBase): 
    value = models.DecimalField(null=False, blank=False, max_digits=20 , decimal_places=4) 

class ParameterNumeric(ParameterBase): 
    minimum = models.DecimalField(null=True, blank=True, max_digits=20 , decimal_places=4)  
    maximum = models.DecimalField(null=True, blank=True, max_digits=20 , decimal_places=4) 

Таким образом, после синхронизации я мог видеть, что Джанго создал 4 таблицы -

CREATE TABLE "calc_parameterconstant_m2m" (
    "id" serial NOT NULL PRIMARY KEY, 
    "from_parameterconstant_id" integer NOT NULL, 
    "to_parameterconstant_id" integer NOT NULL, 
    UNIQUE ("from_parameterconstant_id", "to_parameterconstant_id") 
) 
; 
CREATE TABLE "calc_parameterconstant" (
    "id" serial NOT NULL PRIMARY KEY, 
    "description" varchar(200) NOT NULL, 
    "sort_order" numeric(6, 4) NOT NULL, 
    "value" numeric(20, 4) NOT NULL 
) 
; 
ALTER TABLE "calc_parameterconstant_m2m" ADD CONSTRAINT "from_parameterconstant_id_refs_id_f893bb67" FOREIGN KEY ("from_parameterconstant_id") REFERENCES "calc_parameterconstant" ("id") DEFERRABLE INITIALLY DEFERRED; 
ALTER TABLE "calc_parameterconstant_m2m" ADD CONSTRAINT "to_parameterconstant_id_refs_id_f893bb67" FOREIGN KEY ("to_parameterconstant_id") REFERENCES "calc_parameterconstant" ("id") DEFERRABLE INITIALLY DEFERRED; 

CREATE TABLE "calc_parameternumeric_m2m" (
    "id" serial NOT NULL PRIMARY KEY, 
    "from_parameternumeric_id" integer NOT NULL, 
    "to_parameternumeric_id" integer NOT NULL, 
    UNIQUE ("from_parameternumeric_id", "to_parameternumeric_id") 
) 
; 
CREATE TABLE "calc_parameternumeric" (
    "id" serial NOT NULL PRIMARY KEY, 
    "description" varchar(200) NOT NULL, 
    "sort_order" numeric(6, 4) NOT NULL, 
    "minimum" numeric(20, 4), 
    "maximum" numeric(20, 4) 
) 

Теперь, это явно не мое намерение - я хочу, чтобы иметь возможность подключить параметр каждого типа параметров других типов. Есть ли способ достичь этой цели, используя Django ORM и наследование модели?

Если модель базового параметра была таблицей на ее собственном языке с отношением «Множество-много» к себе, а вспомогательные таблицы были связаны с неразвязанным отношением один к одному, это могло бы быть хорошим решением здесь базы данных мудрым.

ответ

0

Я думаю, multi-table inheritance решит вашу проблему. Чтобы использовать его, просто удалите abstract = True из подкласса ParameterBase.Meta (или полностью удалите этот подкласс).

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

Например, это будет терпеть неудачу:

p = ParameterBase.objects.get(...) # get a ParameterBase that is a ParameterConstant 
print p.value 

Вместо этого, вы должны сделать это:

p = ParameterConstant.objects.get(...) 
print p.value 

Или это:

p = ParameterBase.objects.get(...) # get a ParameterBase that is a ParameterConstant 
print p.paramaterconstant.value 
+0

что добавленная стоимость с использованием нескольких таблицы модели наследования, а затем обычная один к одному поле в отдельных моделях? – haki

+0

Классы для детей по-прежнему имеют доступ к атрибутам и методам родительского класса. В этом случае, если p является экземпляром параметра ParameterConstant, то p.description делает то, что вы ожидаете. Кроме того, такие вещи, как 'isinstance (p, ParameterBase)' работают как ожидалось, поскольку он использует обычное наследование python. Если вы используете OneToOneField, вам придется явно перейти к вашему «родительскому» классу. Использование OneToOneField не является наследованием. –

+0

еще одна разница, о которой я могу думать, заключается в том, что запрос параметра с наследованием, вероятно, вызовет запрос к обеим таблицам при использовании одного к одному, позволяя ленивую загрузку дополнительных параметров. – haki

0

Одним из способов решения этой проблемы будет следует заменить

m2m = models.ManyToManyField('self',related_name='dependent_on') 

с

m2m = models.ManyToManyField('ParameterBase', related_name='dependent_on') 

но Django не позволит вам создать поле M2M, что указывает на модель, которая не была установлена ​​еще и тот, который является абстрактным. На данный момент ParameterBase - это и то, и другое.

Я хотел бы сделать это как этот

class Parameter(models.Model): 
    id = models.AutoField(primary_key=True)  
    description = models.CharField(max_length=200) 
    sort_order = models.DecimalField(null=False, max_digits=6, decimal_places=4) 

class ParameterType(models.Model): 
    parameter = models.ForeignKey(Parameter) 
    related_parameters = models.ManyToManyField(Parameter,related_name='dependent_on') 

    class Meta: 
     abstract = True 

class ParameterConstant(ParameterType): 
    value = models.DecimalField(null=False, blank=False, max_digits=20 , decimal_places=4) 

class ParameterNumeric(ParameterType): 
    minimum = models.DecimalField(null=True, blank=True, max_digits=20 , decimal_places=4)  
    maximum = models.DecimalField(null=True, blank=True, max_digits=20 , decimal_places=4) 
+0

Это на самом деле довольно интересная идея. разве вам не хватает одной-единственной ссылки между вспомогательными моделями на базовую модель? вы получаете ассоциации из m2m, но вам также нужен базовый параметр текущего подкласса. – haki

+0

@ хаки, ты прав, я обновил свой ответ. – vikki

Смежные вопросы