MyGear - Anpassen der User-Informationen
Da ich eine Multi-User-WebApp bauen möchte, muss ich mich darum kümmern, dass sich User registrieren, einloggen, ausloggen, löschen und ändern können.
Django hat ein eingebautes User-Modell mit wenigen, aber den meistgebräuchlichen Informationen zu Usern. Darunter sind Benutzername, eMail, Passwort, Vor- und Nachname. Für meine App hätte ich gerne zusätzliche Informationen. Außerdem würde ich gerne den Benutzernamen weglassen und ein einloggen mit eMail als Benutzernamen haben. Zusätzliche Informationen sollen zum User gespeichert werden. Ich habe mir überlegt, dass ich für den Anfang folgendes brauche:
- eMail - auch als Benutzername (verpflichtend)
- Passwort (verpflichtend)
- Vor- und Nachname
- Ort
- Avatar-Bild
- Maximale Ausrüstung (später soll es Stufen geben, z.B. manche User können max. 3 Ausrüstungsgegenstände, manche, wie Unterstützer oder Helfer, auch mehr)
Später können noch weitere Felder hinzukommen. Im Prinzip sollte das kein Problem sein, ich bin da optimistisch.
Die Benutzerverwaltung, also das User-Modell und die Interaktion mit dem Benutzer soll in eine eigene App. Also wechsele ich in meinen Projektordner mygear.
python manage.py startapp accounts
In der settings.py des Projekts trage ich dann accounts unter INSTALLED_APPS = [ ein, wie wir das schon bei der Startseite gemacht haben. Am Ende der Datei füge ich noch folgendes ein:
AUTH_USER_MODEL = "accounts.MyUser"
Damit sage ich Django, dass es mein eigenes User-Modell nehmen soll. Der Name MyUser kann frei gewählt werden. Er taucht nur gleich noch mal auf, also aufgepasst, dass Ihr dann den gleichen Namen nehmt.
Dann trage ich in accounts/models.py meine eigenes User-Modell ein. Dafür benutze ich die Funktion AbstractUser, welche das Original-Django-User-Modell als Basis nimmt.
from django.db import models
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
username=None
email=models.EmailField(unique=True)
location=models.CharField(max_length=50,blank=True)
avatar=models.ImageField(upload_to='media/',null=True,blank=True)
maxgear=models.IntegerField(default=3)
USERNAME_FIELD='email'
REQUIRED_FIELDS=[]
objects = UserManager()
Passwort und Name fehlen? Ja, die sollte Django aus dem Standard-Modell übernehmen. Jetzt müssen wir den User Manager anpassen, da ja nun ein Feld, username, fehlt. Dazu füge ich in der models.py noch ein:
from django.contrib.auth.models import AbstractUser, BaseUserManager
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError('eMail required')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
Als nächsten Schritt muss ich mein eigenes User-Modell in die Admin-Oberfläche bekommen. Denn auch dort wird das Feld username erwartet. Dafür wird die admin.py bearbeitet.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.utils.translation import gettext_lazy as _
from .models import MyUser
@admin.register(MyUser)
class UserAdmin(DjangoUserAdmin):
fieldsets=(
(None,{'fields':('email','password')}),
(_('Permissions'),{'fields':('is_active','is_staff','is_superuser','groups','user_permissions')}),
(_('Important dates'),{'fields':('last_login','date_joined')}),
)
add_fieldsets=(
(None,{
'classes':('wide',),
'fields':('email','password1','password2'),
})
)
list_display=('email','first_name','last_name','is_staff')
search_fields=('email','first_name','last_name')
ordering=('email',)
Und dann migriere ich in die Datenbank:
python manage.py makemigrations
python manage.py makemigrate
Um auch unsere hinzugefügten Felder im Admin-Bereich anzeigen zu lassen, kann ich in der admin.py den Bereich fieldsets anpassen.
fieldsets=(
(None,{'fields':('email','password')}),
(_('User data'),{'fields':('location','avatar','maxgear')}),
(_('Permissions'),{'fields':('is_active','is_staff','is_superuser','groups','user_permissions')}),
(_('Important dates'),{'fields':('last_login','date_joined')}),
)
Wie man auf dem Screenshot sieht, ist das komplett flexibel. Ich habe den Bereich "User data" hinzugefügt.
