553 votes

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

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 aussi éventuellement utiliser l'adresse électronique comme nom d'utilisateur (à des fins d'authentification).

J'ai déjà vu un quelques moyens de le faire, mais je n'arrive pas à décider lequel est le meilleur.

31 votes

La plupart des réponses sont périmées/dépréciées. Veuillez consulter stackoverflow.com/a/22856042/781695 & stackoverflow.com/q/14104677/781695 & stackoverflow.com/q/16880461/781695

1 votes

@buffer - La première question à laquelle vous avez fait référence (stackoverflow.com/a/22856042/781695) a été supprimée. Les autres questions sont toujours valables.

3 votes

Pour utiliser l'email au lieu du nom d'utilisateur pour l'authentification, cet article est utile.

314voto

Ryan Duffield Points 7602

La façon la moins pénible et d'ailleurs recommandée par Django de le faire est d'utiliser une propriété OneToOneField(User).

Cela dit, l'extension de django.contrib.auth.models.User fonctionne également mieux maintenant -- depuis le remaniement du code d'héritage de Django dans l'API des modèles.

Je ne voudrais surtout pas modifier la classe User dans l'arbre source de Django et/ou copier et modifier le module auth.

0 votes

Avec cette solution, faut-il utiliser une clé étrangère pour l'utilisateur ou le profil ?

57 votes

Pour information, la nouvelle méthode recommandée (1.0+) est OneToOneField(User). docs.djangoproject.com/fr/dev/topics/auth/

2 votes

Shawn Rider, de PBS, a donné de très bonnes raisons de le faire. no extend django.contrib.auth.models.User. Utilisez OneToOneField(User) à la place.

240voto

Raisins Points 1653

C'est comme ça que je 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 profil d'utilisateur à chaque fois qu'un utilisateur sera enregistré, s'il est créé. Vous pouvez alors utiliser

  user.get_profile().whatever

Voici quelques informations supplémentaires tirées 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 déprécié depuis la v1.5 : https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module

6 votes

Merci pour cet exemple clair, notez que def create_user.... ne fait pas partie de la classe UserProfile et doit être aligné à gauche.

5 votes

Avec cette solution, les autres modèles doivent-ils avoir une clé étrangère vers User ou UserProfile ?

9 votes

Les autres modèles doivent utiliser user = models.ForeignKey( User ) et récupérer l'objet de profil via user.get_profile() . N'oubliez pas de from django.contrib.admin.models import User .

224voto

Ondrej Slinták Points 9922

Un certain temps s'est écoulé depuis 2008 et il est temps de trouver de nouvelles réponses. Depuis Django 1.5, vous serez en mesure de créer une classe d'utilisateur personnalisée. En fait, à l'heure où j'écris ces lignes, elle a déjà été intégrée dans master, vous pouvez donc l'essayer.

Il y a des informations à ce sujet dans docs ou, si vous voulez approfondir le sujet, en cet engagement .

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

Pour les personnes qui ont la flemme 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

0 votes

La fonction create_user ne semble pas stocker le nom d'utilisateur, comment cela se fait-il ? !

6 votes

Parce que dans cet exemple, email est le nom d'utilisateur.

5 votes

Vous devez ajouter unique=True dans le champ de l'adresse électronique pour que USERNAME_FIELD l'accepter

64voto

Riccardo Galli Points 2653

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 la configurer comme classe d'utilisateur actuelle dans votre fichier de configuration.

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

Si vous souhaitez ajouter un grand nombre de 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 devez accéder à la classe utilisateur, n'oubliez pas que les gens peuvent la modifier. Utilisez l'aide officielle pour obtenir la bonne classe

from django.contrib.auth import get_user_model

User = get_user_model()

3 votes

Si vous prévoyez d'utiliser django_social_auth je recommande d'utiliser une relation OneToOne. N'utilisez pas cette méthode, sinon vous risquez de perturber vos migrations.

1 votes

@Nimo : Pouvez-vous préciser ou citer une référence ?

0 votes

@buffer, c'était il y a longtemps, mais je pense que j'ai essayé de combiner le django_social_auth et en définissant le AUTH_USER_MODEL à l'utilisateur social auth. Ensuite, lorsque j'ai exécuté manage.py migrate, mon application a été perturbée. A la place, j'ai utilisé le modèle de l'utilisateur social auth comme une relation OneToOne comme décrit ici : stackoverflow.com/q/10638293/977116

47voto

mojo Points 1473

Il existe une recommandation officielle sur le stockage d'informations supplémentaires sur les utilisateurs . Le Django Book aborde également ce problème dans la section Profils .

1 votes

Sur cette page docs.djangoproject.com/fr/dev/topics/auth/personnalisation est arrivé à la section de l'extension du modèle

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X