Extension du modèle utilisateur avec des champs personnalisés dans Django
-
09-06-2019 - |
Question
Quelle est la meilleure façon d'étendre le modèle User (fourni avec l'application d'authentification de Django) avec des champs personnalisés ?J'aimerais également éventuellement utiliser l'e-mail comme nom d'utilisateur (à des fins d'authentification).
j'ai déjà vu un peu façons pour le faire, mais je n'arrive pas à décider lequel est le meilleur.
La solution
La manière la moins pénible et en fait recommandée par Django de procéder consiste à utiliser un OneToOneField(User)
propriété.
Extension du modèle utilisateur existant
…
Si vous souhaitez stocker des informations relatives à
User
, vous pouvez utiliser un relation individuelle à un modèle contenant les champs pour des informations supplémentaires.Ce modèle individuel est souvent appelé modèle de profil, car il peut stocker des informations non liées à l'authentification sur un utilisateur du site.
Cela dit, étendre django.contrib.auth.models.User
et le supplanter fonctionne aussi...
Remplacement d'un modèle utilisateur personnalisé
Certains types de projets peuvent avoir des exigences d'authentification pour lesquelles le logiciel intégré de Django
User
Le modèle n’est pas toujours approprié.Par exemple, sur certains sites, il est plus logique d’utiliser une adresse e-mail comme jeton d’identification plutôt qu’un nom d’utilisateur.[Éd. : Deux avertissements et une notification suivent, mentionnant qu'il s'agit assez drastique.]
J'éviterais certainement de modifier la classe User réelle dans votre arborescence source Django et/ou de copier et de modifier le module d'authentification.
Autres conseils
Note:cette réponse est obsolète.voir d'autres réponses si vous utilisez Django 1.7 ou version ultérieure.
C'est comme ça que je procède.
#in models.py
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User)
#other fields here
def __str__(self):
return "%s's profile" % self.user
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
#in settings.py
AUTH_PROFILE_MODULE = 'YOURAPP.UserProfile'
Cela créera un profil utilisateur chaque fois qu'un utilisateur est enregistré s'il est créé.Vous pouvez alors utiliser
user.get_profile().whatever
Voici quelques informations supplémentaires provenant de la documentation
http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
Mise à jour: Veuillez noter que AUTH_PROFILE_MODULE
est obsolète depuis la v1.5 : https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module
Eh bien, du temps s'est écoulé depuis 2008 et il est temps d'apporter une nouvelle réponse.Depuis Django 1.5, vous pourrez créer une classe User personnalisée.En fait, au moment où j'écris ceci, il est déjà fusionné dans master, vous pouvez donc l'essayer.
Il y a des informations à ce sujet dans documents ou si vous voulez approfondir la question, dans cet engagement.
Il ne vous reste plus qu'à ajouter AUTH_USER_MODEL
aux paramètres avec le chemin d'accès à la classe d'utilisateurs personnalisée, qui s'étend soit AbstractBaseUser
(version plus personnalisable) ou AbstractUser
(classe User plus ou moins ancienne que vous pouvez étendre).
Pour les personnes qui ont la flemme de cliquer, voici un exemple de code (tiré de documents):
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
class MyUserManager(BaseUserManager):
def create_user(self, email, date_of_birth, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=MyUserManager.normalize_email(email),
date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, date_of_birth, password):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
u = self.create_user(username,
password=password,
date_of_birth=date_of_birth
)
u.is_admin = True
u.save(using=self._db)
return u
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['date_of_birth']
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def __unicode__(self):
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
@property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
Depuis Django 1.5, vous pouvez facilement étendre le modèle utilisateur et conserver une seule table dans la base de données.
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import ugettext_lazy as _
class UserProfile(AbstractUser):
age = models.PositiveIntegerField(_("age"))
Vous devez également le configurer comme classe d'utilisateurs actuelle dans votre fichier de paramètres
# supposing you put it in apps/profiles/models.py
AUTH_USER_MODEL = "profiles.UserProfile"
Si vous souhaitez ajouter de nombreuses préférences d'utilisateurs, l'option OneToOneField peut être un meilleur choix.
Une note pour les personnes développant des bibliothèques tierces :si vous avez besoin d'accéder à la classe d'utilisateurs, n'oubliez pas que les utilisateurs peuvent la modifier.Utilisez l'assistant officiel pour obtenir la bonne classe
from django.contrib.auth import get_user_model
User = get_user_model()
Il existe une recommandation officielle sur stocker des informations supplémentaires sur les utilisateurs.Le Django Book aborde également ce problème dans la section Profils.
Celle ci-dessous est une autre approche pour étendre un utilisateur.Je pense que c'est plus clair, facile et lisible qu'au-dessus de deux approches.
http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/
En utilisant l'approche ci-dessus :
- tu n'as pas besoin d'utiliseruser.get_profile().newattribute Pour accéder aux informations supplémentaires liées à l'utilisateur
- Vous pouvez simplement accéder directement à de nouveaux attributs supplémentaires viautilisateur.nouvelattribut
Vous pouvez simplement étendre le profil utilisateur en créant une nouvelle entrée à chaque fois que l'utilisateur est créé à l'aide des signaux de sauvegarde post-Django.
modèles.py
from django.db.models.signals import *
from __future__ import unicode_literals
class userProfile(models.Model):
userName = models.OneToOneField(User, related_name='profile')
city = models.CharField(max_length=100, null=True)
def __unicode__(self): # __str__
return unicode(self.userName)
def create_user_profile(sender, instance, created, **kwargs):
if created:
userProfile.objects.create(userName=instance)
post_save.connect(create_user_profile, sender=User)
Cela créera automatiquement une instance d'employé lors de la création d'un nouvel utilisateur.
Si vous souhaitez étendre le modèle utilisateur et ajouter des informations supplémentaires lors de la création de l'utilisateur, vous pouvez utiliser Django-betterforms (http://django-betterforms.readthedocs.io/en/latest/multiform.html).Cela créera un formulaire d'ajout d'utilisateur avec tous les champs définis dans le modèle userProfile.
modèles.py
from django.db.models.signals import *
from __future__ import unicode_literals
class userProfile(models.Model):
userName = models.OneToOneField(User)
city = models.CharField(max_length=100)
def __unicode__(self): # __str__
return unicode(self.userName)
formulaires.py
from django import forms
from django.forms import ModelForm
from betterforms.multiform import MultiModelForm
from django.contrib.auth.forms import UserCreationForm
from .models import *
class profileForm(ModelForm):
class Meta:
model = Employee
exclude = ('userName',)
class addUserMultiForm(MultiModelForm):
form_classes = {
'user':UserCreationForm,
'profile':profileForm,
}
vues.py
from django.shortcuts import redirect
from .models import *
from .forms import *
from django.views.generic import CreateView
class addUser(CreateView):
form_class = addUserMultiForm
template_name = "addUser.html"
success_url = '/your url after user created'
def form_valid(self, form):
user = form['user'].save()
profile = form['profile'].save(commit=False)
profile.userName = User.objects.get(username= user.username)
profile.save()
return redirect(self.success_url)
addUser.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="." method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Add</button>
</form>
</body>
</html>
URL.py
from django.conf.urls import url, include
from appName.views import *
urlpatterns = [
url(r'^add-user/$', addUser.as_view(), name='addDistributor'),
]
Extension du modèle utilisateur Django (UserProfile) comme un pro
J'ai trouvé ceci très utile : lien
Un extrait:
à partir de django.contrib.auth.models importer l'utilisateur
class Employee(models.Model):
user = models.OneToOneField(User)
department = models.CharField(max_length=100)
>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department
Nouveau dans Django 1.5, vous pouvez désormais créer votre propre modèle utilisateur personnalisé (ce qui semble être une bonne chose à faire dans le cas ci-dessus).Faire référence à 'Personnalisation de l'authentification dans Django'
Probablement la nouvelle fonctionnalité la plus intéressante de la version 1.5.
C'est ce que je fais et c'est à mon avis le moyen le plus simple de le faire.définissez un gestionnaire d'objets pour votre nouveau modèle personnalisé puis définissez votre modèle.
from django.db import models
from django.contrib.auth.models import PermissionsMixin, AbstractBaseUser, BaseUserManager
class User_manager(BaseUserManager):
def create_user(self, username, email, gender, nickname, password):
email = self.normalize_email(email)
user = self.model(username=username, email=email, gender=gender, nickname=nickname)
user.set_password(password)
user.save(using=self.db)
return user
def create_superuser(self, username, email, gender, password, nickname=None):
user = self.create_user(username=username, email=email, gender=gender, nickname=nickname, password=password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class User(PermissionsMixin, AbstractBaseUser):
username = models.CharField(max_length=32, unique=True, )
email = models.EmailField(max_length=32)
gender_choices = [("M", "Male"), ("F", "Female"), ("O", "Others")]
gender = models.CharField(choices=gender_choices, default="M", max_length=1)
nickname = models.CharField(max_length=32, blank=True, null=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
REQUIRED_FIELDS = ["email", "gender"]
USERNAME_FIELD = "username"
objects = User_manager()
def __str__(self):
return self.username
N'oubliez pas d'ajouter cette ligne de code dans votre settings.py
:
AUTH_USER_MODEL = 'YourApp.User'
C'est ce que je fais et ça marche toujours.