Si en alguna ocasión al trabajar con Django, y correr una migración recibes el error Provide a one-off default now, entonces este post puede serte de ayuda.
Este error, suele suceder cuando añadimos a un modelo ya existente, una nueva llave (ForeingKey), con un valor determinado.
En este post mostraré dos formas de hacerlo.
Siguiendo la documentación, Añadir una ForeignKey (non-nullable)
en Django se divide en tres pasos:
Veamos primero la situación inicial:
class Post(models.Model):
name = models.CharField(max_length=100)
Paso 1.
Primero se añade la nueva llave, donde primero definiremos null, como null=TRUE
y luego desde consola correremos makemigrations()
.
Esto creará una nueva migración que añade el campo que hemos creado.a la tabla, por tanto ahora tenemos una nueva columna con todas sus filas con valor Null.
class Post(models.Model):
name = models.CharField(max_length=100)
category = models.ForeignKey(Category, null=True, on_delete=models.CASCADE))
$ python manage.py makemigrations
Migrations for 'mi_App':
mi_App/migrations/0002_post_category.py
- Add field author to post
Paso 2
Ahora correremos nuevamente makemigrations
, creando una una nueva migración vacía (makemigrations --empty)
.
$ python manage.py makemigrations --empty -n mi_App assign_category
Migrations for 'mi_App':
mi_App/migrations/0003_assign_category.py
Ahora editamos esta migración para que contenga los datos que deseamos, y es en este momento donde de acuerdo a nuestra necesidades colocaremos el valor que debe tener la nueva Foreign key
.
from django.db import migrations
def assign_category(apps, schema_editor):
Category= apps.get_model('category', 'Category')
Post = apps.get_model('mi_App', 'Post')
Post.objects.all().update(category=category) # and bulk update all posts.
class Migration(migrations.Migration):
dependencies = [...]
operations = [
migrations.RunPython(assign_category, migrations.RunPython.noop),
]
Paso 3
En el tercer paso modificaremos la nueva ForeignKey
en nuestro modelo, eliminando la posibilidad de valor nulo:
null=False
class Post(models.Model):
name = models.CharField(max_length=100)
category = models.ForeignKey(Category, null=False, on_delete=models.CASCADE))
Y creamos una nueva migración corriendo nuevamente makemigrations
.
$ python manage.py makemigrations mi_App -n post_category_non_null
Recibirás este mensaje:
You are trying to change the nullable field 'author' on something. to non-nullable without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)
3) Quit, and let me add a default in models.py
Seleccionamos la opción 2 y problema resuelto.
Migrations for 'mi_App':
something/migrations/0004_post_author_non_null.py
- Alter field category on post
Este es el camino más largo, que sugiere la documentación, pero como siempre hay una posibilidad mas corta:
- En la carpeta migraciones eliminamos todas la migraciones existentes,
- corremos nuevamente makemigrations, con las modificaciones nuevas.
- corremos migrate
- creamos nuevamente el superusuario
Con esto quedaría resuelto.
Espero sinceramente, que esto sirva de ayuda a alguien .
……..y para cuando a ti te estén rompiendo el alma, ya el tiempo habrá cicatrizado mis heridas.
A. Torres
Un saludo