python - tutorial - Modelos abstractos django versus herencia regular
django windows (5)
De hecho, quiero saber la diferencia entre una clase de modelo que hereda de una clase abstracta django (Meta: abstract = True) y una clase simple de Python que hereda de decir, ''objeto'' (y no modelos.Modelo).
Django solo generará tablas para subclases de models.Model
. models.Model
, entonces el primero ...
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)
... hará que se genere una sola tabla, en la línea de ...
CREATE TABLE myapp_employee
(
id INT NOT NULL AUTO_INCREMENT,
first_name VARCHAR(255) NOT NULL,
title VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
... mientras que el último ...
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)
... no causará que se generen tablas.
Puede usar herencia múltiple para hacer algo como esto ...
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)
... que crearía una tabla, pero ignorará los campos definidos en la clase User
, por lo que terminarás con una tabla como esta ...
CREATE TABLE myapp_employee
(
id INT NOT NULL AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
Además de la sintaxis, ¿cuál es la diferencia entre usar un modelo abstracto django y usar una herencia simple de Python con modelos django? ¿Pros y contras?
ACTUALIZACIÓN: Creo que mi pregunta fue mal interpretada y recibí respuestas sobre la diferencia entre un modelo abstracto y una clase heredada de django.db.models.Model. De hecho, quiero saber la diferencia entre una clase de modelo que hereda de una clase abstracta django (Meta: abstract = True) y una clase simple de Python que hereda de decir, ''objeto'' (y no modelos.Modelo).
Aquí hay un ejemplo:
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(...
La principal diferencia es cómo se crean las tablas de bases de datos para los modelos. Si usa inheritance sin abstract = True
Django creará una tabla separada para el modelo padre y el secundario que contienen los campos definidos en cada modelo.
Si usa abstract = True
para la clase base, Django solo creará una tabla para las clases que hereden de la clase base, sin importar si los campos están definidos en la clase base o en la clase heredada.
Los pros y los contras dependen de la arquitectura de su aplicación. Dado el siguiente ejemplo de modelos:
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(...)
Si la clase de Publishable
no es abstracta, Django creará una tabla para publicables con el title
y la date
las columnas y tablas separadas para BlogEntry
e Image
. La ventaja de esta solución sería que puede consultar en todos los publicables los campos definidos en el modelo base, sin importar si son entradas de blog o imágenes. Pero por lo tanto, Django tendrá que hacer combinaciones si, por ejemplo, consultas para imágenes ... Si hace Publishable
abstract = True
Django no creará una tabla para Publishable
, sino solo para entradas de blog e imágenes, que contengan todos los campos (también los heredados) . Esto sería útil porque no se necesitarían uniones para una operación como get.
También vea la documentación de Django sobre la herencia del modelo .
La principal diferencia es cuando heredas la clase de usuario. Una versión se comportará como una clase simple, y la otra se comportará como un modelo de Django.
Si hereda la versión base de "objeto", su clase Employee será simplemente una clase estándar, y first_name no pasará a formar parte de una tabla de base de datos. No puede crear un formulario ni usar ninguna otra característica de Django con él.
Si hereda la versión models.Model, su clase Employee tendrá todos los métodos de un Model Django y heredará el campo first_name como un campo de base de datos que se puede usar en un formulario.
De acuerdo con la documentación, un Modelo abstracto "proporciona una manera de factorizar información común en el nivel de Python, mientras que solo crea una tabla de base de datos por modelo hijo a nivel de base de datos".
Solo quería agregar algo que no he visto en otras respuestas.
A diferencia de las clases de Python, el ocultamiento del nombre de campo no está permitido con la herencia del modelo.
Por ejemplo, he experimentado problemas con un caso de uso de la siguiente manera:
Tenía un modelo heredado de la PermissionMixin de django PermissionMixin :
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
# ...
Luego tuve mi mixin que, entre otras cosas, quería que anulara el campo related_name
del groups
. Entonces fue más o menos así:
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.''))
Estaba usando estas 2 mezclas de la siguiente manera:
class Member(PermissionMixin, WithManagedGroupMixin):
pass
Así que sí, esperaba que esto funcionara, pero no fue así. Pero el problema era más grave porque el error que recibía no apuntaba en absoluto a las modelos, no tenía idea de qué estaba pasando mal.
Al tratar de resolver esto, decidí al azar cambiar mi mixin y convertirlo en un modelo abstracto mixin. El error cambió a esto:
django.core.exceptions.FieldError: Local field ''groups'' in class ''Member'' clashes with field of similar name from base class ''PermissionMixin''
Como puede ver, este error explica qué está sucediendo.
Esta fue una gran diferencia, en mi opinión :)
Un modelo abstracto crea una tabla con todo el conjunto de columnas para cada subchild, mientras que el uso de la herencia de Python "simple" crea un conjunto de tablas vinculadas (también conocido como "herencia de tablas múltiples"). Considere el caso en el que tiene dos modelos:
class Vehicle(models.Model):
num_wheels = models.PositiveIntegerField()
class Car(Vehicle):
make = models.CharField(…)
year = models.PositiveIntegerField()
Si Vehicle
es un modelo abstracto, tendrá una sola tabla:
app_car:
| id | num_wheels | make | year
Sin embargo, si usa la herencia simple de Python, tendrá dos tablas:
app_vehicle:
| id | num_wheels
app_car:
| id | vehicle_id | make | model
Donde vehicle_id
es un enlace a una fila en app_vehicle
que también tendría el número de ruedas para el automóvil.
Ahora, Django combinará esto en forma de objeto para que pueda acceder a num_wheels
como un atributo en Car
, pero la representación subyacente en la base de datos será diferente.
Actualizar
Para abordar su pregunta actualizada, la diferencia entre heredar de una clase abstracta de Django y heredar del object
de Python es que la primera se trata como un objeto de base de datos (por lo que las tablas se sincronizan con la base de datos) y tiene el comportamiento de un Model
. Heredar de un object
simple de Python le da a la clase (y sus subclases) ninguna de esas cualidades.