codicoop / boilerplate_django

Plantilla pels nous projectes web amb Django.
GNU General Public License v3.0
0 stars 0 forks source link

Superuser by extra service #13

Closed perepicornell closed 2 years ago

perepicornell commented 2 years ago

He creat aquest PR en resposta a https://github.com/codicoop/boilerplate_django/issues/12

Pensaments sobre el tema:

Altres comentaris que podríem comentar a la propera trucada si vols:

nabiu256 commented 2 years ago

Error previ

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.

Solució

Val res, mirant pel codi font de Django 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 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.