Django에서 사용자 정의 필드로 사용자 모델 확장


442

사용자 정의 필드로 사용자 모델 (Django의 인증 앱과 함께 제공)을 확장하는 가장 좋은 방법은 무엇입니까? 이메일을 사용자 이름으로 사용하고 싶습니다 (인증 목적으로).

나는 이미 가지 방법 을 보았지만 어느 것이 가장 좋은 지 결정할 수 없습니다.


24
대부분의 답변은 오래되었거나 더 이상 사용되지 않습니다. stackoverflow.com/a/22856042/781695 및 stackoverflow.com/q/14104677/781695 및 stackoverflow.com/q/16880461/781695
사용자

@buffer-링크 한 첫 번째 질문 (stackoverflow.com/a/22856042/781695)이 삭제되었습니다. 다른 것들은 여전히 ​​유효합니다.
Tony

3
인증을 위해 사용자 이름 대신 이메일을 사용하려면 이 기사 가 유용합니다.


꽤 장고가 @Farinha를 발표되기 전에 문제는 2008 년에 물었다보고 매료
Tessaracter

답변:


253

가장 고통스럽고 실제로 장고가 권장하는 방법은 OneToOneField(User)속성을 통하는 것 입니다.

기존 사용자 모델 확장

와 관련된 정보를 저장하려는 경우 추가 정보를위한 필드가 포함 된 모델에 일대일 관계User사용할 수 있습니다 . 이 일대일 모델을 사이트 모델에 대한 인증되지 않은 관련 정보를 저장할 수 있으므로 종종 프로필 모델이라고합니다.

즉, django.contrib.auth.models.User그것을 확장 하고 대체하는 것도 효과가 있습니다 ...

사용자 정의 사용자 모델 대체

일부 종류의 프로젝트에는 Django의 내장 User모델이 항상 적합하지 않은 인증 요구 사항이있을 수 있습니다 . 예를 들어, 일부 사이트에서는 사용자 이름 대신 전자 메일 주소를 식별 토큰으로 사용하는 것이 더 합리적입니다.

[Ed : 두 가지 경고와 알림 이 이어지는데, 이는 상당히 과감한 것 입니다.]

Django 소스 트리에서 실제 사용자 클래스를 변경하거나 인증 모듈을 복사 및 변경하지 마십시오.


51
참고로 새로운 (1.0+) 권장 방법은 OneToOneField (User) docs.djangoproject.com/en/dev/topics/auth/…입니다.
Dave Forgac

2
PBS의 Shawn Rider는 django.contrib.auth.models.User를 확장 해서는 안되는 몇 가지 좋은 이유를 제시했습니다 . 대신 OneToOneField (User)를 사용하십시오.
pydanny

2
user = models.ForeignKey(User, unique=True)이것과 동일 user = models.OneToOneField(User)합니까? 나는 최종 효과가 같다고 생각할까요? 그러나 백엔드의 구현이 다를 수 있습니다.
Sam Stoelinga

7
누구든지 Shawn Riders의 주장 / 추론에 연결할 수 있습니까?
Jeremy Blanchard

1
다음 은 django 1.7 문서로 사용자 모델을 확장하는 방법에 대한 추가 정보입니다.
Derek Adair

226

참고 :이 답변은 더 이상 사용되지 않습니다. Django 1.7 이상을 사용하는 경우 다른 답변을 참조하십시오.

이것이 내가하는 방법입니다.

#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'

이렇게하면 사용자를 만들 때마다 사용자 프로필을 만들 수 있습니다. 그런 다음 사용할 수 있습니다

  user.get_profile().whatever

문서에서 더 많은 정보가 있습니다.

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

업데이트 : 제발 노트 AUTH_PROFILE_MODULE1.5 버전부터 사용되지 않습니다 : https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module


6
명확한 예를 들어 주셔서 감사합니다. def create_user ....는 UserProfile 클래스의 일부가 아니므로 왼쪽으로 정렬해야합니다.
PhoebeB

5
이 솔루션을 사용하면 다른 모델의 ForeignKey to User 또는 UserProfile?
andrewrk

9
다른 모델은을 사용 user = models.ForeignKey( User )하여 프로파일 객체를 검색 해야합니다 user.get_profile(). 기억하십시오 from django.contrib.admin.models import User.
Craig Trader

1
이 방법을 사용하면 일반적인 정보 (이름, 비밀번호) 및 사용자 정의 정보를 검색 할 때 분리해야하거나 한 번에 수행 할 수있는 방법이 있습니까? 새로운 사용자 생성에도 동일합니까?
Martin Trigaux

5
이 답변 및 의견이 오래되었습니다. 예 : AUTH_PROFILE_MODULE은 사용되지 않습니다.User
사용자

196

글쎄요, 2008 년 이후 어느 정도 시간이 지났고 이제는 새로운 답변을 얻을 시간입니다. Django 1.5부터 사용자 정의 사용자 클래스를 만들 수 있습니다. 실제로, 나는 이것을 쓸 때 이미 마스터로 병합되어 있으므로 시도해 볼 수 있습니다.

그것에 대한 몇 가지 정보가 있습니다 이 커밋 문서 있거나 더 깊이 파고 싶다면 여기에 커밋하십시오 .

당신이해야 할 추가 AUTH_USER_MODEL사용자 정의 사용자 클래스에 대한 경로를 사용하여 설정에 하기 만하면됩니다 AbstractBaseUser(사용자 정의 가능 버전) 또는 AbstractUser확장 할 수있는 더 오래되거나 덜 사용되는 사용자 클래스).

클릭하기 게으른 사람들을 위해 다음 코드 예제 ( 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

create_user 함수가 사용자 이름을 저장하지 않는 것 같습니다!
Orca

6
이 예에서는 email사용자 이름 이므로
Ondrej Slinták

5
수락 unique=True하려면 이메일 필드 에 추가해야 USERNAME_FIELD합니다
Richard de Wit

안녕하세요, 당신이 말한 것처럼 사용자 정의 사용자를 만들려고했지만 사용자 정의 사용자 전자 메일의 전자 메일을 사용하여 로그인 할 수 없었습니다. 왜 그런지 말하지 않겠습니까?
Lionel

구체적이지 않으면 당신을 정말로 도울 수 없습니다. 새 질문을 작성하면 더 좋습니다.
Ondrej Slinták

47

Django 1.5부터는 사용자 모델을 쉽게 확장하고 데이터베이스에 단일 테이블을 유지할 수 있습니다.

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"))

설정 파일에서 현재 사용자 클래스로 구성해야합니다.

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

많은 사용자 환경 설정을 추가하려는 경우 OneToOneField 옵션이 더 나은 선택 일 수 있습니다.

타사 라이브러리를 개발하는 사람들을위한 참고 사항 : 사용자 클래스에 액세스해야하는 경우 사람들이 라이브러리를 변경할 수 있음을 기억하십시오. 올바른 도우미를 얻기 위해 공식 도우미를 사용하십시오

from django.contrib.auth import get_user_model

User = get_user_model()

3
를 사용하려는 경우 django_social_authOneToOne 관계를 사용하는 것이 좋습니다. 이 방법을 사용하지 마십시오. 그렇지 않으면 마이그레이션이 엉망이됩니다.
니모

@Nimo : 참조를 정교하게하거나 인용 할 수 있습니까
사용자

@buffer, 오랜 시간이 지났지 만 django_social_auth플러그인을 결합 하고 AUTH_USER_MODEL을 소셜 인증 사용자에게 정의 하려고 시도한 것 같습니다 . 그런 다음 manage.py 마이그레이션을 실행하면 앱이 엉망이되었습니다. 대신 소셜 인증 사용자 모델을 여기에 설명 된 OneToOne 관계로 사용했습니다. stackoverflow.com/q/10638293/977116
Nimo

3
아마도 Changing this setting after you have tables created is not supported by makemigrations and will result in you having to manually write a set of migrations to fix your schema소스 와 관련이있을 것입니다 : docs.djangoproject.com/en/dev/topics/auth/customizing/…
사용자


23

아래는 사용자를 확장하는 또 다른 방법입니다. 두 가지 접근 방식보다 더 명확하고 쉽고 읽기 쉽다고 생각합니다.

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

위의 접근 방식을 사용하십시오.

  1. 사용자와 관련된 추가 정보에 액세스 하기 위해 user.get_profile (). newattribute 를 사용할 필요는 없습니다 .
  2. user.newattribute 를 통해 추가 속성에 직접 액세스 할 수 있습니다.

1
모델에서 직접 사용하는 것이 아니라 User 개체의 상속을 기반으로 Scott의 접근 방식이 훨씬 좋습니다. 이 방법이 현명하지 않다고 말할 수 있습니까?
BozoJoe

1
@BozoJoe-방금 덤프 데이터를 가져 오는이 문제에 부딪 쳤습니다.이 방법을 사용한 결과 : stackoverflow.com/questions/8840068/…
Ben Regenspan

15

Django post save 신호를 사용하여 사용자를 만들 때마다 새 항목을 만들어 사용자 프로필을 간단하게 확장 할 수 있습니다

models.py

from django.db.models.signals import *
from __future__ import unicode_literals

class UserProfile(models.Model):

    user_name = models.OneToOneField(User, related_name='profile')
    city = models.CharField(max_length=100, null=True)

    def __unicode__(self):  # __str__
        return unicode(self.user_name)

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        userProfile.objects.create(user_name=instance)

post_save.connect(create_user_profile, sender=User)

새 사용자가 생성되면 직원 인스턴스가 자동으로 생성됩니다.

사용자 모델을 확장하고 사용자를 작성하는 동안 추가 정보를 추가하려는 경우 django-betterforms ( http://django-betterforms.readthedocs.io/en/latest/multiform.html )를 사용할 수 있습니다 . UserProfile 모델에 정의 된 모든 필드가있는 사용자 추가 양식이 작성됩니다.

models.py

from django.db.models.signals import *
from __future__ import unicode_literals

class UserProfile(models.Model):

    user_name = models.OneToOneField(User)
    city = models.CharField(max_length=100)

    def __unicode__(self):  # __str__
        return unicode(self.user_name)

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 = ('user_name',)


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 = "add-user.html"
    success_url = '/your-url-after-user-created'

    def form_valid(self, form):
        user = form['user'].save()
        profile = form['profile'].save(commit=False)
        profile.user_name = 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='add-user'),
]

이 답변에 감사드립니다. 나는 여전히 urls.py .. 모든 힌트를 함께 연결하는 방법을 이해하기 위해 고심하고 있습니다.
sal

@sal 지금 당신이 확인할 수있는 URL 예제를 추가했습니다
Atul Yadav

감사!!. 그것은 많은 도움이됩니다. 좋은 예
Sunny Chaudhari

@AtulYadav .. 사용한 Django의 버전은 무엇입니까?
Rido

8

프로처럼 장고 사용자 모델 (UserProfile) 확장

나는 이것이 매우 유용 발견했습니다 링크를

추출물 :

django.contrib.auth.models에서 사용자 가져 오기

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

2
끝난. 왜 -1인지 이해하지 못합니다. 이 경우 공감보다 편집이 더 좋습니다.
Massimo Variolo

3

Django 1.5의 새로운 기능으로, 이제 자신 만의 사용자 정의 사용자 모델을 만들 수 있습니다 (위의 경우에 좋은 것으로 보입니다). 'Django에서 인증 사용자 정의'를 참조하십시오

1.5 릴리스에서 가장 멋진 새로운 기능 일 것입니다.


1
네 확실합니다. 그러나 필요한 경우가 아니면 이것을 피해야합니다. 이 질문에 대한 이유를 위해 자신을 구현하는 것은 문서화 된 결과에 익숙한 경우에 완벽하게 유효합니다. 단순히 필드를 추가하려면 일반 사용자 모델과의 관계를 권장 합니다.
gertvdijk

2

이것이 내가하는 일이며 내 생각으로는 가장 간단한 방법입니다. 새로운 사용자 정의 모델에 대한 객체 관리자를 정의한 다음 모델을 정의하십시오.

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

이 코드 줄을 다음에 추가하는 것을 잊지 마십시오 settings.py.

AUTH_USER_MODEL = 'YourApp.User'

이것이 내가하는 일이며 항상 작동합니다.



0

간단하고 효과적인 접근 방식은 models.py입니다.

from django.contrib.auth.models import User
class CustomUser(User):
     profile_pic = models.ImageField(upload_to='...')
     other_field = models.CharField()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.