Closed perepicornell closed 2 years ago
He estat provant una bona estona i aprenent sobre data migrations i al final m'he acabat trobant amb un problema que no sé resoldre.
El codi que he intentant implementar és una cosa així
def generate_superuser(apps, schema_editor):
User = apps.get_model("users.User")
User.objects.create_superuser(
email=settings.DJANGO_SUPERUSER_EMAIL,
password=settings.DJANGO_SUPERUSER_PASSWORD,
)
print("\nInitial superuser created\n")
class Migration(migrations.Migration):
dependencies = [
('users', '0001_initial'),
]
operations = [
migrations.RunPython(generate_superuser)
]
El problema sorgeix de que, a l'agafar el model amb el get_model
, sembla ser que el Manager
no té el mètode create_superuser
(ni el create_user
).
AttributeError: 'Manager' object has no attribute 'create_superuser'
Llegint coses per internet al respecte, l'únic que he pogut entendre com a possiblitat de per què passa això és un tema de que el Manager
no es configura fins després de les migracions, o una cosa per l'estil.
En tot cas el següent que he provat és implementar a lo bèstia el que faria el create_superuser
com hem parlat abans en trucada. Aquí sorgeix un únic problema que és a l'hora de posar la password, aquesta sempre s'ha de posar a través del mètode set_password
(per tal de que Django gestioni correctament el hashing). Malauradament, aquesta mètode tampoc existeix si no tenim el Manager, i no he vist com reproduir-la.
Val res, mirant pel codi font de Django sí que puc accedir a la funció que és necessària. El mètode set_password
no està disponible, però set_password
és bàsicament dues línies de codi: una crida a un mètode make_password
(que és un classmethod i per tant sí és accessible) i un set a un camp.
Llavors el que he fet és purament reproduïr el que create_superuser
faria així:
from django.contrib.auth.models import BaseUserManager
from django.contrib.auth.hashers import make_password
def generate_superuser(apps, schema_editor):
User = apps.get_model("users.User")
email=settings.DJANGO_SUPERUSER_EMAIL
password=settings.DJANGO_SUPERUSER_PASSWORD
user = User()
user.email = BaseUserManager.normalize_email(email)
user.password = make_password(password)
user.is_staff = True
user.is_superuser = True
user.save()
i ja. Poso el missatge aquest aquí perquè quedi ben localitzat i mínimament documentat, però com m'has demanat, ho poso directament a develop per quan necessitis fer pull.
Havia posat una pregunta a stackoverflow aquí i trobo interessant deixar-la linkada aquí per tal de veure les respostes de la gent, ja que ja han sortit temes interessants.
He creat aquest PR en resposta a https://github.com/codicoop/boilerplate_django/issues/12
Pensaments sobre el tema:
migrate
el pots tirar tantes vegades com vulguis que cada migració només s'executarà una vegada. Per tant, si tanques contenidors preservant la BD (sense ferdown' ), quan els tornis a aixecar i s'executi el
develop_django_boilerplate_startup_commands, el
migrate` únicament dirà "no migrations to apply", i per tant no intentarà tornar a crear l'usuari.try
.makemigrations
no s'ha d'executar mai de forma automatitzada. És responsabilitat de qui desenvolupa un canvi que, si aquest afecta a la BD, generi les migracions, les comprovi bé i les inclogui dins del repositori. Si algú s'oblida de fer això, el que interessa és que quan executi l'aplicació, peti, no que de forma silenciosa i automàtica li faci aquests passos. Si vols en parlem més i t'explico exemples concrets dels problemes que pot generar.Altres comentaris que podríem comentar a la propera trucada si vols:
__latest__
.