Extension du modèle utilisateur avec des champs personnalisés dans Django

Quel est le meilleur moyen d'étendre le modèle utilisateur (fourni avec L'application d'authentification de Django) avec des champs personnalisés? Je voudrais également utiliser l'email comme nom d'utilisateur (à des fins d'authentification).

J'ai déjà vu un quelques façons, mais ne peut pas décider qui est le meilleur.

373
demandé sur Dmitriy 2008-09-04 20:19:49

10 réponses

La façon la moins douloureuse et la moins recommandée par Django est de le faire via une propriété OneToOneField(User).

Extension du modèle utilisateur existant

Si vous souhaitez stocker des informations relatives à User, vous pouvez utiliser une relation un-à-un à un modèle contenant les champs pour plus d'informations. Ce modèle one-To-one est souvent appelé un modèle de profil, car il peut stocker des informations non liées à l'authentification sur un site utilisateur.

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 modèle User intégré à Django n'est pas toujours approprié. Par exemple, sur certains sites, il est plus logique d'utiliser une adresse e-mail que votre jeton d'identification au lieu d'un nom d'utilisateur.

[Ed: deux avertissements et une notification suivent , de mentionner que c'est assez drastique.]

Je resterais certainement à l'écart de la modification de la classe Utilisateur réelle dans votre arborescence source Django et / ou de la copie et de la modification du module auth.

216
répondu Ryan Duffield 2015-06-13 00:38:44

Note: cette réponse est obsolète. voir d'autres réponses si vous utilisez Django 1.7 ou plus tard.

C'est comme ça que je le fais.

#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 userprofile chaque fois qu'un utilisateur est enregistré s'il est créé. Vous pouvez ensuite utiliser

  user.get_profile().whatever

Voici quelques informations supplémentaires des docs

Http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users

Mise À Jour: {[5] } Veuillez noter que AUTH_PROFILE_MODULE est obsolète depuis la version 1.5: https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module

213
répondu Raisins 2016-12-14 11:49:34

Eh bien, un certain temps s'est écoulé depuis 2008 et il est temps pour une nouvelle réponse. Depuis Django 1.5, vous pourrez créer une classe utilisateur personnalisée. En fait, au moment où j'écris ceci, il est déjà fusionné dans master, donc vous pouvez l'essayer.

Il y a des informations à ce sujet dans docs ou si vous voulez approfondir, dans ce commit.

Tout ce que vous avez à faire est d'ajouter AUTH_USER_MODEL aux paramètres avec le chemin d'accès à la classe utilisateur personnalisée, qui s'étend soit AbstractBaseUser (plus personnalisable version) ou AbstractUser (Classe utilisateur plus ou moins ancienne que vous pouvez étendre).

Pour les personnes qui sont paresseuses de cliquer, voici un exemple de code (tiré de docs):

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
180
répondu Ondrej Slinták 2014-06-24 15:41:18

Il existe une recommandation officielle sur le stockage d'informations supplémentaires sur les utilisateurs . Le Livre Django traite également de ce problème dans la section Profiles .

41
répondu Dmitry Mukhin 2010-05-17 13:52:24

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 en tant que Classe utilisateur actuelle dans votre fichier de paramètres

# supposing you put it in apps/profiles/models.py
AUTH_USER_MODEL = "profiles.UserProfile"

Si vous voulez ajouter beaucoup de préférences des utilisateurs, l'option OneToOneField peut être un meilleur choix.

Une note pour les personnes qui développent des bibliothèques tierces: si vous avez besoin d'accéder à la classe user, n'oubliez pas que les personnes peuvent la modifier. Utilisez l'aide officielle pour obtenir le droit classe

from django.contrib.auth import get_user_model

User = get_user_model()
39
répondu Riccardo Galli 2013-04-20 21:56:43

Le ci-dessous est une autre approche pour étendre un utilisateur. Je pense que c'est plus clair,facile, lisible que deux approches.

Http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/

En utilisant l'approche ci-dessus:

  1. vous n'avez pas besoin d'utiliser utilisateur.get_profile ().newattribute pour accéder aux informations supplémentaires lié à l'utilisateur
  2. , vous pouvez simplement accéder directement nouveaux attributs via utilisateur.newattribute
21
répondu Rama Vadakattu 2009-04-01 13:01:09

Vous pouvez simplement étendre le profil utilisateur en créant une nouvelle entrée chaque fois que l'utilisateur est créé en utilisant django post save signals

Models.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.

Models.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)

Forms.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,
    }

Views.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>

Urls.py

from django.conf.urls import url, include
from appName.views import *
urlpatterns = [
        url(r'^add-user/$', addUser.as_view(), name='addDistributor'),
]
10
répondu Atul Yadav 2016-10-04 15:44:25

Extension du modèle Utilisateur Django (UserProfile) comme un Pro

J'ai trouvé cela très utile: lien

Un extrait:

De django.contrib.auth.importation de modèles de 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
7
répondu Massimo Variolo 2016-04-13 14:38:18

Nouveau dans Django 1.5, vous pouvez maintenant créer votre propre modèle utilisateur personnalisé (ce qui semble être une bonne chose à faire dans le cas ci-dessus). Référez-vous à 'Personnalisation de L'authentification dans Django'

Probablement la nouvelle fonctionnalité la plus cool sur la version 1.5.

2
répondu chhantyal 2013-03-12 10:10:13

C'est ce que je fais et c'est à mon avis le moyen le plus simple de le faire. définir un gestionnaire d'objets pour votre nouveau modèle personnalisé, puis de définir 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.

0
répondu Milad Kh 2018-07-25 05:00:38