Подтвердить что ты не робот

Абстрактные модели джанго и регулярное наследование

Помимо синтаксиса, какая разница между использованием абстрактной модели django и использованием простого наследования Python с моделями django? Плюсы и минусы?

ОБНОВЛЕНИЕ: Я думаю, что мой вопрос был неправильно понят, и я получил ответы на разницу между абстрактной моделью и классом, который наследуется от django.db.models.Model. Я действительно хочу знать разницу между классом модели, который наследуется от абстрактного класса django (Meta: abstract = True) и простого класса Python, который наследует, скажем, "объект" (а не модели .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(...
4b9b3361

Ответ 1

Я действительно хочу знать разницу между классом модели, который наследуется от абстрактного класса django (Meta: abstract = True) и простой класс Python, который наследует, например, "объект" (а не models.Model).

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)
);

Ответ 2

Абстрактная модель создает таблицу со всем набором столбцов для каждого подраздела, тогда как использование "простого" наследования Python создает набор связанных таблиц (например, "наследование на нескольких таблицах" ). Рассмотрим случай, когда у вас две модели:

class Vehicle(models.Model):
  num_wheels = models.PositiveIntegerField()


class Car(Vehicle):
  make = models.CharField(…)
  year = models.PositiveIntegerField()

Если Vehicle - абстрактная модель, у вас будет одна таблица:

app_car:
| id | num_wheels | make | year

Однако, если вы используете обычное наследование Python, у вас будет две таблицы:

app_vehicle:
| id | num_wheels

app_car:
| id | vehicle_id | make | model

Где vehicle_id - ссылка на строку в app_vehicle, которая также будет иметь количество колес для автомобиля.

Теперь Django прекрасно сочетает это в объектной форме, поэтому вы можете получить доступ к num_wheels как атрибут на Car, но базовое представление в базе данных будет иным.


Update

Чтобы ответить на ваш обновленный вопрос, разница между наследованием от абстрактного класса Django и наследованием от Python object заключается в том, что он рассматривается как объект базы данных (поэтому таблицы для него синхронизируются с базой данных), и он имеет поведение a Model. Наследование с простого Python object не дает классу (и его подклассам) ни одного из этих качеств.

Ответ 3

Просто хотел добавить что-то, чего я не видел в других ответах.

В отличие от классов python, скрытие имени поля не разрешено с наложением модели.

Например, я экспериментировал с вариантами использования следующим образом:

У меня была модель, наследующая от django auth PermissionMixin:

class PermissionsMixin(models.Model):
    """
    A mixin class that adds the fields and methods necessary to support
    Django 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

    # ...

Тогда у меня был мой mixin, который среди прочего я хотел, чтобы он переопределил 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

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

Пытаясь решить эту проблему, я беспорядочно решил изменить свой mixin и преобразовать его в абстрактный модель mixin. Ошибка изменилась на следующее:

django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin'

Как вы можете видеть, эта ошибка объясняет, что происходит.

Это была огромная разница, на мой взгляд:)

Ответ 4

Основное отличие заключается в том, как создаются таблицы баз данных для моделей. Если вы используете наследование без 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 по наследованию модели.

Ответ 5

Основное отличие заключается в том, что вы наследуете класс User. Одна версия будет вести себя как простой класс, а другая будет вести себя как режим Django.

Если вы наследуете базовую версию "объект", ваш класс Employee будет просто стандартным классом, а first_name не станет частью таблицы базы данных. Вы не можете создать форму или использовать с ней какие-либо другие функции Django.

Если вы наследуете версию models.Model, ваш класс Employee будет иметь все методы Django Model, и он наследует поле first_name как поле базы данных, которое можно использовать в форме.

В соответствии с документацией Абстрактная модель "дает возможность разделить общую информацию на уровне Python, в то же время создавая только одну базу данных таблица на дочернюю модель на уровне базы данных."