Модель наследования Джанго.Как решить? - PullRequest
1 голос
/ 06 октября 2010

У меня есть приложение со следующей моделью

class Contact(models.Model):
     lastname = models.CharField(max_length=200)
     firstname = models.CharField(max_length=200)
     ...

class Journalist(Contact):
     pass

У меня есть Contact в моей базе данных, и я хотел бы, чтобы оно стало Journalist.

В raw sql все выглядит просто, как insert into app_journalist values (25624);.В этом примере 25624 - это идентификатор существующего контакта.Кажется, все работает нормально, и приложение django кажется счастливым.

Однако я бы хотел сделать то же самое с django ORM.Я пробовал несколько мыслей, например, принудительно вводить идентификатор журналиста (Journalist(id=25624)), но он создает новый контакт, а не ссылку на существующий.

Возможно ли это сделать с помощью Django ORM?Как?

Заранее спасибо за помощь

Ответы [ 3 ]

3 голосов
/ 06 октября 2010

Один из способов решения этой проблемы (без изменения структуры модели) - установить для атрибута contact_ptr экземпляра Journalist соответствующий экземпляр Contact. Например,

contact = Contact.objects.get(pk = 25624)
journalist = Journalist(contact_ptr = contact)
journalist.save()

Это становится легче понять, если вы сначала посмотрите на таблицу app_journalist. Он имеет только один столбец, contact_ptr_id. Поэтому, когда вы выполняете insert into app_journalist values (25624), вы устанавливаете contact_ptr_id = 25624 на уровне SQL. Соответственно, вы должны установить contact_ptr = <instance of Contact> на уровне ORM.

Обновление

Существуют и другие способы решения проблемы, но они потребуют изменений в существующих моделях. Как @ bugspy.net указал , вы можете использовать общие отношения. Также вы можете объявить дополнительное поле type, чтобы указать, является ли контакт журналистом, коллегой и т. Д.

Обновление 2

Также взгляните на этот демонстрационный фрагмент полный код ), который позволяет использовать полиморфное наследование (SQLAlchemy уже делает это).

Обновление 3

Как отметил сам @luc (см. Комментарий ниже)

journalist = Journalist(contact_ptr = contact)

одного будет недостаточно. Это перезапишет firstname и lastname из contact в "". Чтобы избежать этого, вы должны явно назначить каждому полю Journalist.

2 голосов
/ 06 октября 2010
Фреймворк

Django Contenttypes действительно удобен.Вы можете использовать его для представления различных типов контактов:

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class Contact(models.Model):
     lastname = models.CharField(max_length=200)
     firstname = models.CharField(max_length=200)
     content_object = generic.GenericForeignKey('content_type', 'object_id')
0 голосов
/ 06 октября 2010

Наследование на уровне модели, как правило, не очень хорошая идея. Большинство ORM позволяют вам сделать это. Большинство ORM даже гордятся тем, что могут это сделать. На уровне модели знаменитая « предпочитает композицию наследованию » - это как никогда верно.

В вашем случае вместо того, чтобы сказать: "Журналист - это человек" , вы могли бы вместо этого сказать: "У человека есть работа, которая в данном случае является журналистом", Это будет представлено классом Person, составленным из класса Job. Одной из должностей может стать «журналист».

Композиционный подход позволяет вам сменить человека или даже иметь несколько заданий.

Конечно, это не дает прямого ответа на ваш вопрос, но другие ответы уже довольно хороши!

...