Estoy buscando hacer esto:
class Place(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class LongNamedRestaurant(Place): # Subclassing `Place`.
name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length.
food_type = models.CharField(max_length=25)
Esta es la versión que me gustaría usar (aunque estoy abierto a cualquier sugerencia): http://docs.djangoproject.com/en/dev/topics/db/models/#id7
¿Es esto compatible con Django? Si no es así, ¿hay alguna forma de lograr resultados similares?
python
django
django-inheritance
Johnny 5
fuente
fuente
Respuestas:
Respuesta actualizada: como señalaron las personas en los comentarios, la respuesta original no respondía correctamente a la pregunta. De hecho, solo el
LongNamedRestaurant
modelo se creó en la base de datos,Place
no lo fue.Una solución es crear un modelo abstracto que represente un "lugar", por ejemplo.
AbstractPlace
y heredar de él:Lea también la respuesta de @Mark , él da una gran explicación de por qué no puede cambiar los atributos heredados de una clase no abstracta.
(Tenga en cuenta que esto solo es posible desde Django 1.10: antes de Django 1.10, no era posible modificar un atributo heredado de una clase abstracta).
fuente
Place
era abstracto, por lo tanto, no se creó en la base de datos. Pero OP quería que ambosPlace
yLongNamedRestaurant
se crearan en la base de datos. Por lo tanto, actualicé mi respuesta para agregar elAbstractPlace
modelo, que es el modelo "base" (es decir, abstracto) tantoPlace
comoLongNamedRestaurant
heredado. Ahora ambosPlace
yLongNamedRestaurant
se crean en la base de datos, como lo solicitó OP.No, no lo es :
fuente
User._meta.get_field('email').required = True
podría funcionar, no estoy seguro._meta
MyParentClass._meta.get_field('email').blank = False
email
Eso no es posible a menos que sea abstracto, y aquí está la razón:
LongNamedRestaurant
también es aPlace
, no solo como una clase sino también en la base de datos. La mesa de lugar contiene una entrada para cada puroPlace
y para cadaLongNamedRestaurant
.LongNamedRestaurant
simplemente crea una tabla adicional confood_type
y una referencia a la tabla de lugar.Si lo hace
Place.objects.all()
, también obtendrá cada lugar que sea unLongNamedRestaurant
, y será una instancia dePlace
(sinfood_type
). EntoncesPlace.name
yLongNamedRestaurant.name
comparten la misma columna de base de datos y, por lo tanto, deben ser del mismo tipo.Creo que esto tiene sentido para los modelos normales: cada restaurante es un lugar y debería tener al menos todo lo que tiene ese lugar. Quizás esta consistencia sea también la razón por la que no era posible para modelos abstractos antes de 1.10, aunque no daría problemas de base de datos allí. Como señala @lampslave, fue posible en 1.10. Personalmente, recomendaría cuidado: si Sub.x anula a Super.x, asegúrese de que Sub.x sea una subclase de Super.x; de lo contrario, Sub no se puede utilizar en lugar de Super.
Soluciones alternativas : puede crear un modelo de usuario personalizado (
AUTH_USER_MODEL
) que implica bastante duplicación de código si solo necesita cambiar el campo de correo electrónico. Alternativamente, puede dejar el correo electrónico como está y asegurarse de que sea obligatorio en todos los formularios. Esto no garantiza la integridad de la base de datos si otras aplicaciones la usan y no funciona al revés (si desea que el nombre de usuario no sea obligatorio).fuente
Consulte https://stackoverflow.com/a/6379556/15690 :
fuente
Pegó su código en una aplicación nueva, agregó la aplicación a INSTALLED_APPS y ejecutó syncdb:
Parece que Django no lo admite.
fuente
Esta pieza de código súper genial le permite 'anular' campos en clases padre abstractas.
Cuando los campos se han eliminado de la clase principal abstracta, puede redefinirlos según lo necesite.
Este no es mi propio trabajo. Código original desde aquí: https://gist.github.com/specialunderwear/9d917ddacf3547b646ba
fuente
Quizás podrías lidiar con contrib_to_class:
Syncdb funciona bien. No probé este ejemplo, en mi caso simplemente anulo un parámetro de restricción, así que ... ¡espera y verás!
fuente
Place._meta.get_field('name').max_length = 255
en el cuerpo de la clase debería hacer el truco, sin anular__init__()
. También sería más conciso.Sé que es una pregunta antigua, pero tuve un problema similar y encontré una solución:
Tuve las siguientes clases:
Pero quería que se requiriera el campo de imagen heredado de Year mientras se mantenía el campo de imagen de la superclase anulable. Al final utilicé ModelForms para hacer cumplir la imagen en la etapa de validación:
admin.py:
Parece que esto solo es aplicable para algunas situaciones (ciertamente, donde necesita hacer cumplir reglas más estrictas en el campo de subclase).
Alternativamente, puede usar el
clean_<fieldname>()
método en lugar declean()
, por ejemplo, sitown
se requiere completar un campo :fuente
No puede anular los campos del modelo, pero se logra fácilmente anulando / especificando el método clean (). Tuve el problema con el campo de correo electrónico y quería hacerlo único en el nivel de modelo y lo hice así:
El mensaje de error es capturado por el campo de formulario con el nombre "correo electrónico"
fuente
Mi solución es tan simple como la siguiente
monkey patching
, observe cómo cambié elmax_length
atributo foname
campo en elLongNamedRestaurant
modelo:fuente