Помимо синтаксиса, в чем разница между использованием абстрактной модели django и использованием простого наследования Python с моделями django? За и против?
ОБНОВЛЕНИЕ: я думаю, что мой вопрос был неправильно понят, и я получил ответы о разнице между абстрактной моделью и классом, наследуемым от django.db.models.Model. На самом деле я хочу знать разницу между классом модели, который наследуется от абстрактного класса django (Meta: abstract = True), и простым классом Python, который наследуется, скажем, от «объекта» (а не от models.Model).
Вот пример:
class User(object):
first_name = models.CharField(..
def get_username(self):
return self.username
class User(models.Model):
first_name = models.CharField(...
def get_username(self):
return self.username
class Meta:
abstract = True
class Employee(User):
title = models.CharField(...
Ответы:
Django будет генерировать таблицы только для подклассов
models.Model
, поэтому первый ...class User(models.Model): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Meta: abstract = True class Employee(User): title = models.CharField(max_length=255)
... вызовет создание единой таблицы по строкам ...
CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, first_name VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) );
... тогда как последний ...
class User(object): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Employee(User): title = models.CharField(max_length=255)
... не приведет к созданию таблиц.
Вы можете использовать множественное наследование, чтобы сделать что-то вроде этого ...
class User(object): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Employee(User, models.Model): title = models.CharField(max_length=255)
... который создаст таблицу, но проигнорирует поля, определенные в
User
классе, поэтому вы получите такую таблицу ...CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) );
источник
models.Model
, поэтому поля, определенные в суперклассе, не будут взяты (если они не являются также подклассамиmodels.Model
).ModelBase
«S__new__
вызова, он выполняет начальную проверку класса» атрибутов, проверка , если значение атрибута имеетcontribute_to_class
признак -Fields
что вы определяете в Django все сделать, чтобы они включены в специальный словарь,contributable_attrs
который в конечном итоге передается во время миграции для генерации DDL.Абстрактная модель создает таблицу со всем набором столбцов для каждого дочернего ребенка, тогда как использование «простого» наследования Python создает набор связанных таблиц (также известный как «многотабличное наследование»). Рассмотрим случай, когда у вас есть две модели:
class Vehicle(models.Model): num_wheels = models.PositiveIntegerField() class Car(Vehicle): make = models.CharField(…) year = models.PositiveIntegerField()
Если
Vehicle
это абстрактная модель, у вас будет одна таблица:Однако, если вы используете простое наследование Python, у вас будет две таблицы:
Где
vehicle_id
ссылка на строку, вapp_vehicle
которой также указано количество колес для автомобиля.Теперь Django красиво объединит это в объектную форму, чтобы вы могли получить доступ
num_wheels
как атрибутCar
, но базовое представление в базе данных будет другим.Обновить
Чтобы ответить на ваш обновленный вопрос, разница между наследованием от абстрактного класса Django и наследования от Python
object
заключается в том, что первый рассматривается как объект базы данных (поэтому таблицы для него синхронизируются с базой данных), и он имеет поведениеModel
. Наследование от простого Python неobject
дает классу (и его подклассам) ни одного из этих качеств.источник
models.OneToOneField(Vehicle)
также было бы равносильно наследованию класса модели, верно? И это привело бы к созданию двух отдельных таблиц, не так ли?num_wheels
атрибут в acar
, тогда как с aOneToOneField
вам придется делать это, разыменовывая себя.app_car
таблицы, чтобы она также имелаnum_wheels
поле вместоvehicle_id
указателя?Основное отличие заключается в том, как создаются таблицы базы данных для моделей. Если вы используете наследование без
abstract = True
Django, будет создана отдельная таблица для родительской и дочерней модели, в которой будут храниться поля, определенные в каждой модели.Если вы используете
abstract = True
базовый класс, Django создаст таблицу только для классов, которые наследуются от базового класса - независимо от того, определены ли поля в базовом классе или в наследующем классе.Плюсы и минусы зависят от архитектуры вашего приложения. Учитывая следующие примеры моделей:
class Publishable(models.Model): title = models.CharField(...) date = models.DateField(....) class Meta: # abstract = True class BlogEntry(Publishable): text = models.TextField() class Image(Publishable): image = models.ImageField(...)
Если
Publishable
класс не является абстрактным, Django создаст таблицу для публикуемых материалов со столбцамиtitle
и,date
а также отдельные таблицы дляBlogEntry
иImage
. Преимущество этого решения состоит в том, что вы можете запрашивать поля, определенные в базовой модели, среди всех публикуемых объектов , независимо от того, являются ли они записями в блогах или изображениями. Но поэтому Django должен будет выполнять соединения, если вы, например, выполняете запросы для изображений ... Если созданиеPublishable
abstract = True
Django не будет создавать таблицу дляPublishable
записей блога и изображений, а только для записей в блогах и изображений, содержащих все поля (также унаследованные). Это было бы удобно, потому что для такой операции, как get, не требуется никаких соединений.Также см . Документацию Django о наследовании моделей .
источник
Просто хотел добавить то, чего не видел в других ответах.
В отличие от классов python, скрытие имени поля не разрешено при наследовании модели.
Например, я экспериментировал со следующим вариантом использования:
У меня была модель, унаследованная от PermissionMixin django :
class PermissionsMixin(models.Model): """ A mixin class that adds the fields and methods necessary to support Django's Group and Permission model using the ModelBackend. """ is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_('Designates that this user has all permissions without ' 'explicitly assigning them.')) groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'his/her group.')) user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True, help_text='Specific permissions for this user.') class Meta: abstract = True # ...
Тогда у меня был подмешать , который среди других вещей , которые я хотел, чтобы это переопределить
related_name
вgroups
поле. Так было примерно так:class WithManagedGroupMixin(object): groups = models.ManyToManyField(Group, verbose_name=_('groups'), related_name="%(app_label)s_%(class)s", blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'his/her group.'))
Я использовал эти 2 миксина следующим образом:
class Member(PermissionMixin, WithManagedGroupMixin): pass
Так что да, я ожидал, что это сработает, но этого не произошло. Но проблема была более серьезной, потому что ошибка, которую я получал, вообще не указывала на модели, я понятия не имел, что пошло не так.
Пытаясь решить эту проблему, я случайно решил изменить свой миксин и преобразовать его в миксин абстрактной модели. Ошибка изменилась на это:
django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin'
Как видите, эта ошибка объясняет, что происходит.
На мой взгляд, это была огромная разница :)
источник
Основное отличие заключается в том, когда вы наследуете класс User. Одна версия будет вести себя как простой класс, а другая - как модель Django.
Если вы унаследуете базовую «объектную» версию, ваш класс Employee будет просто стандартным классом, а first_name не станет частью таблицы базы данных. Вы не можете создать форму или использовать с ней какие-либо другие функции Django.
Если вы наследуете версию models.Model, ваш класс Employee будет иметь все методы модели Django и унаследует поле first_name как поле базы данных, которое можно использовать в форме.
Согласно документации, абстрактная модель «предоставляет способ вычленить общую информацию на уровне Python, в то же время создавая только одну таблицу базы данных для каждой дочерней модели на уровне базы данных».
источник
Я предпочитаю абстрактный класс в большинстве случаев, потому что он не создает отдельную таблицу, и ORM не нужно создавать объединения в базе данных. А использовать абстрактный класс в Django довольно просто.
class Vehicle(models.Model): title = models.CharField(...) Name = models.CharField(....) class Meta: abstract = True class Car(Vehicle): color = models.CharField() class Bike(Vehicle): feul_average = models.IntegerField(...)
источник