Si como yo te ha pasado que después de un largo tiempo de desarrollo de un sistema, te das cuenta que tus modelos pueden tener una mejor organización utilizando herencia de modelos los que ayuda a tener un código mas simple y ordenado ademas de evitar duplicar código en los modelos.
Por poner un ejemplo supongamos que tenemos tres modelos en una aplicación llamada schools (School, Student y Class)
from django.db import models
class School(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return '%s' % (self.name)
class Student(models.Model):
name = models.CharField(max_length=20)
school = models.ForeignKey(
School, null=True, blank=True, on_delete=models.CASCADE
)
def __str__(self):
return '%s' % (self.name)
class Class(models.Model):
name = models.CharField(max_length=20)
students = models.ManyToManyField(Student)
def __str__(self):
return '%s' % (self.name)
La aplicación tiene un año en producción (nuestros modelos tienen registros en la base de datos), por alguna razón necesitas Generar un modelo llamado People del cual heredara el modelo Student
Podríamos pensar en modificar nuestros modelos, generar migraciones y migrar de esta forma
from django.db import models
class People(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return '%s' % (self.name)
class Student(People):
school = models.ForeignKey(
School, null=True, blank=True, on_delete=models.CASCADE
)
Si hacemos esto nos va a marcar este error
You are trying to add a non-nullable field 'people_ptr' to student without a default; we can't do that (the database needs something to populate existing rows).
Como Solucionamos este problema
- Agregamos el nuevo modelo de People y creamos las migraciones con
python manage.py makemigration
class People(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return '%s' % (self.name)
Esto nos generara un archivo de migración como este
# Generated by Django 2.0.1 on 2018-10-18 23:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('schools', '0003_auto_20181018_1618'),
]
operations = [
migrations.CreateModel(
name='People',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=20)),
],
),
]
- Este lo modificamos a que quede de esta forma
# Generated by Django 2.0.1 on 2018-10-18 23:59
from django.db import migrations, models
def load_info(apps, schema_editor):
People = apps.get_model("schools", "People")
Student = apps.get_model("schools", "Student")
for student in Student.objects.all():
People.objects.create(
id=student.people_ptr,
name=student.name,
)
class Migration(migrations.Migration):
atomic = False
dependencies = [
('schools', '0003_auto_20181018_1618'),
]
operations = [
migrations.CreateModel(
name='People',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=20)),
],
),
migrations.RenameField(
model_name='student',
old_name='id',
new_name='people_ptr',
),
migrations.RunPython(load_info),
migrations.RemoveField(
model_name='student',
name='name',
),
migrations.AlterField(
model_name='student',
name='people_ptr',
field=models.OneToOneField(auto_created=True, on_delete=models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='schools.People'),
),
]
- Modificamos nuestro modelo Student
Quitando el campo de name y definiendo que hereda del modelo People
class Student(People):
school = models.ForeignKey(
School, null=True, blank=True, on_delete=models.CASCADE
)
- migramos con el comando de
python manage.py migrate
Con estos paso deberíamos de tener nuestros modelos funcionando.
Espero les sea útil este aporte.
Curso Básico de Django v2