2015-05-27 5 views
0

У меня возникла проблема с разработкой моего сайта Django.Django Наследование из классов

from django.db import models 

class TitlePost(models.Model): 
    title_name = models.CharField(max_length=100, unique=True) 
    title_body = models.TextField(max_length=30000) 
    title_why = models.TextField(max_length=250, null=True) 
    title_publication_date = models.DateTimeField('date') 
    likes = models.IntegerField(default=0) 
    dislikes = models.IntegerField(default=0) 


    def __unicode__(self): 
     return self.title_name 


class TopTitlesPostPage(models.Model): 
    title_post = models.OneToOneField(TitlePost) 
    hello = models.CharField(max_length=100, unique=True) 

    def __unicode__(self): 
     return self.hello 

class NewTitlesPostPage(models.Model): 
    title_post = models.OneToOneField(TitlePost) 
    hello = models.CharField(max_length=100, unique=True) 

    def __unicode__(self): 
     return self.hello 

Почему не TopTitlesPostPage и NewTitlesPostPage наследует все атрибуты из TitlePost? Например, если я попытаюсь вызвать likes в моем шаблоне, используя TopTitlesPostPage, он не будет выполняться, потому что атрибут likes не наследуется. OneToOneField как-то связано с проблемой? Я прочитал, что создание TitlePost мета-класса поможет, но мне нужно, чтобы в моей базе данных была таблица. Я действительно хочу, чтобы все они имели таблицу в моей базе данных. Опять же, возможно, я приближаюсь к этому неправильно, и я должен использовать только TitlePost в качестве модели для генерации всего?

ответ

4

Поведение, которое вы хотели бы видеть, называется multi table inheritance. Каждый дочерний класс внутренне заканчивается тем же, что вы написали, поэтому с одним полем в базовый класс TitlePost, но он внутренне управляется django.

Если вы множественное наследование как код ниже вы сможете написать:

k=TopTitlesPostPage.objects.create(hello="Hello",title_name="Heh") 

Это означает, что поля будут непосредственно доступны.

from django.db import models 

class TitlePost(models.Model): 
    title_name = models.CharField(max_length=100, unique=True) 
    title_body = models.TextField(max_length=30000) 
    title_why = models.TextField(max_length=250, null=True) 
    title_publication_date = models.DateTimeField('date') 
    likes = models.IntegerField(default=0) 
    dislikes = models.IntegerField(default=0) 


    def __unicode__(self): 
     return self.title_name 


class TopTitlesPostPage(TitlePost): 
    hello = models.CharField(max_length=100, unique=True) 

    def __unicode__(self): 
     return self.hello 

class NewTitlesPostPage(TitlePost): 
    hello = models.CharField(max_length=100, unique=True) 

    def __unicode__(self): 
     return self.hello 

В случае, если вы никогда на самом деле будет ссылаться на базовый класс TitlePost, но только его дети, возможно, было бы более целесообразным сделать `TitlePost abstract:

class TitlePost(models.Model): 
    title_name = models.CharField(max_length=100, unique=True) 
    title_body = models.TextField(max_length=30000) 
    title_why = models.TextField(max_length=250, null=True) 
    title_publication_date = models.DateTimeField('date') 
    likes = models.IntegerField(default=0) 
    dislikes = models.IntegerField(default=0) 

    class Meta: 
     abstract = True 
    def __unicode__(self): 
     return self.title_name 

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

Для огромных запросов это также будет иметь значение в производительности, поскольку ORM необходимо будет выполнить меньше JOIN операций.

Невозможно установить внешние ключи для абстрактных моделей в Django. Однако вы можете установить внешние ключи для не абстрактного базового класса. Единственное ограничение заключается в том, что обратное отношение внешнего ключа вернет экземпляры базового класса. Вы можете обойти это ограничение, используя django-polymorphic.

Джанго Полиморфные позволяет запрашивать объекты базового класса, но получают экземпляры класса ребенка:

>>> Project.objects.create(topic="Department Party") 
>>> ArtProject.objects.create(topic="Painting with Tim", artist="T. Turner") 
>>> ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter") 

>>> Project.objects.all() 
[ <Project:   id 1, topic "Department Party">, 
    <ArtProject:  id 2, topic "Painting with Tim", artist "T. Turner">, 
    <ResearchProject: id 3, topic "Swallow Aerodynamics", supervisor "Dr. Winter"> ] 

Чтобы использовать Джанго полиморфные вам нужно только объявить свои модели с полиморфной моделью в качестве базового класса:

from django.db import models 
from polymorphic import PolymorphicModel 

class ModelA(PolymorphicModel): 
    field1 = models.CharField(max_length=10) 

class ModelB(ModelA): 
    field2 = models.CharField(max_length=10) 

class ModelC(ModelB): 
    field3 = models.CharField(max_length=10) 

Внешние ключи также возвращают экземпляры дочерних классов, что действительно здорово, если вы пытаетесь быть полиморфными.

# The model holding the relation may be any kind of model, polymorphic or not 
class RelatingModel(models.Model): 
    many2many = models.ManyToManyField('ModelA') # ManyToMany relation to a polymorphic model 

>>> o=RelatingModel.objects.create() 
>>> o.many2many.add(ModelA.objects.get(id=1)) 
>>> o.many2many.add(ModelB.objects.get(id=2)) 
>>> o.many2many.add(ModelC.objects.get(id=3)) 

>>> o.many2many.all() 
[ <ModelA: id 1, field1 (CharField)>, 
    <ModelB: id 2, field1 (CharField), field2 (CharField)>, 
    <ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ] 

Примите во внимание, что эти запросы будут slightly less performant.

+0

Ничего себе, спасибо за всю информацию; это действительно помогает! Я определенно поиграю с этим методом! Поэтому, исходя из эффективности, я полагаю, что создание абстрактного класса для всех - лучший выбор, чем принятие полиморфного маршрута? Что бы вы выбрали между ними и почему? Если вы не возражаете ответить. – tear728

+0

Когда дело доходит до производительности, никогда не оптимизируйте преждевременно. Как правило, вы только хотите принять это во внимание, когда у вас есть узкое место в базе данных. Полиморфный маршрут позволяет вам выполнять правильный полиморфизм, что означает программирование без утверждений и в полной мере использует утиную печать и обычно полезно, когда вы создаете приложения, которые должны быть расширяемы в будущем. Я бы использовал его для любого проекта, который больше, чем просто демо, но у него не будет десятков тысяч записей или сотен дополнительных моделей. –

+0

Очень интересно. Я обязательно буду помнить об этом для будущих ссылок. Еще раз спасибо за информацию! – tear728

0

Вы должны иметь TopTitlesPostPage и NewTitlesPostPage расширить базовый класс TitlePost как так ...

class TopTitlesPostPage(models.Model) 

Вам не нужно OneToOneField если вы наследование от базового класса, так как атрибуты TitlePost будут доступны вам в подклассе. Если вы хотите сделать TitlePost аннотацию (вы не можете объявить экземпляр этого класса, только наследовать от него), вы должны добавить его в мета-класс

class TitlePost(models.Model): 
    class Meta: 
     abstract = True 

Вот ссылка на documentation.

+0

Не следует 'class TopTitlesPostPage (models.Model)' be 'class TopTitlesPostPage (TitlePost)'? – cpburnz

+0

@Stefan Bossbaly будет ли базовый класс создавать таблицу в базе данных, даже если это мета? – tear728

1

U нужно расширить классы нравится следующим образом:

class TopTitlesPostPage(TitlePost): 

U можно добавить еще и наследовать от нескольких моделей, просто mentionin г все модели разделенные запятой! Это все поля из моделей будут созданы в классе ребенка, а

EDIT:

Пути я бы сделать это, чтобы создать абстрактный класс, который содержит все общие поля и распространить его в TitlePost , TopTitlesPostPagea и NewTitlesPostPage

+0

На самом деле я пробовал это раньше, и по какой-то причине это не сработало. Может, я сделал что-то не так. – tear728

+0

Вы определили TitlePost как абстрактный? – Abhishek

+0

Я сделал, но так как это было мета, это не создало бы таблицу в базе данных. Опять же, я не сразу наследовал так же, как из базового класса после того, как я сделал его мета-классом, и вместо этого использовал отношение 'OneToOneField'. Я попробую! – tear728