Django में कस्टम फ़ील्ड के साथ उपयोगकर्ता मॉडल का विस्तार


442

कस्टम फ़ील्ड के साथ उपयोगकर्ता मॉडल (Django के प्रमाणीकरण ऐप के साथ बंडल) का विस्तार करने का सबसे अच्छा तरीका क्या है? मैं संभवतः ईमेल का उपयोग उपयोगकर्ता नाम (प्रमाणीकरण उद्देश्यों के लिए) के लिए भी करना चाहूंगा।

मैंने पहले से ही इसे करने के कुछ तरीके देखे हैं , लेकिन यह तय नहीं कर सकता कि कौन सा सबसे अच्छा है।


24
अधिकांश उत्तर पुराने / पदावनत हैं। कृपया देखें stackoverflow.com/a/22856042/781695 और stackoverflow.com/q/14104677/781695 और stackoverflow.com/q/16880461/781695
उपयोगकर्ता

@ बफ़र - पहला सवाल जिसे आपने (stackoverflow.com/a/22856042/781695) से जोड़ा था, अब हटा दिया गया है। अन्य अभी भी मान्य हैं।
टोनी

3
प्रमाणीकरण के लिए उपयोगकर्ता नाम के बजाय ईमेल का उपयोग करने के लिए, यह लेख उपयोगी है।


Django के रिलीज़ होने से पहले मैं 2008 में पूछे गए सवाल को देखकर काफी रोमांचित था। @ फरिनाहा
Tessaracter

जवाबों:


253

ऐसा करने का सबसे कम दर्दनाक और वास्तव में Django- अनुशंसित तरीका एक OneToOneField(User)संपत्ति के माध्यम से है ।

मौजूदा उपयोगकर्ता मॉडल का विस्तार

...

यदि आप से संबंधित जानकारी संग्रहीत करना चाहते हैं User, तो आप अतिरिक्त जानकारी के लिए फ़ील्ड वाले मॉडल से एक -से-एक संबंध का उपयोग कर सकते हैं । इस एक-से-एक मॉडल को अक्सर एक प्रोफ़ाइल मॉडल कहा जाता है, क्योंकि यह साइट उपयोगकर्ता के बारे में गैर-सामान्य संबंधित जानकारी संग्रहीत कर सकता है।

यह कहा, विस्तार django.contrib.auth.models.Userऔर supplanting यह भी काम करता है ...

कस्टम उपयोगकर्ता मॉडल को प्रतिस्थापित करना

कुछ प्रकार की परियोजनाओं में प्रमाणीकरण की आवश्यकता हो सकती है जिसके लिए Django का निर्मित Userमॉडल हमेशा उपयुक्त नहीं होता है। उदाहरण के लिए, कुछ साइटों पर यह एक उपयोगकर्ता नाम के बजाय अपनी पहचान टोकन के रूप में एक ईमेल पते का उपयोग करने के लिए अधिक समझ में आता है।

[एड: दो चेतावनियाँ और एक अधिसूचना का पालन करें , यह उल्लेख करते हुए कि यह बहुत कठोर है ।]

मैं निश्चित रूप से आपके Django स्रोत ट्री और / या प्रतिलिपि बनाने और वास्तविक मॉड्यूल को बदलने में वास्तविक उपयोगकर्ता वर्ग को बदलने से दूर रहूंगा।


51
FYI करें नई (1.0+) अनुशंसित विधि OneToOneField (उपयोगकर्ता) docs.djangoproject.com/en/dev/topics/auth/…
डेव फोर्गैक

2
पीबीएस के शॉन राइडर ने वास्तव में कुछ अच्छे कारण दिए कि आपको django.contrib.auth.models.User का विस्तार क्यों नहीं करना चाहिए । इसके बजाय OneToOneField (उपयोगकर्ता) का उपयोग करें।
pydanny

2
user = models.ForeignKey(User, unique=True)क्या यह वैसा ही है user = models.OneToOneField(User)? मुझे लगता है कि अंतिम प्रभाव समान होगा? लेकिन शायद बैकएंड में कार्यान्वयन अलग है।
सैम स्टोइलिंगा

7
क्या कोई शॉन राइडर्स के तर्क / तर्क को उससे जोड़ सकता है?
जेरेमी ब्लैंचर्ड

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_MODULEv1.5 के बाद से पदावनत किया गया है: https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module


6
स्पष्ट उदाहरण के लिए धन्यवाद, ध्यान दें कि create_user को हराया .... .... UserProfile वर्ग का हिस्सा नहीं है और इसे बाईं ओर संरेखित किया जाना चाहिए।
फोबे

5
इस समाधान के साथ अन्य मॉडल ForeignKey को उपयोगकर्ता या UserProfile को देना चाहिए?
andrewrk

9
अन्य मॉडलों का उपयोग करना चाहिए user = models.ForeignKey( User ), और के माध्यम से प्रोफ़ाइल वस्तु को पुनः प्राप्त करना चाहिए user.get_profile()। याद रखना from django.contrib.admin.models import User
क्रेग ट्रेडर

1
इस पद्धति का उपयोग करके, जब मुझे सामान्य जानकारी (नाम, पासवर्ड) प्राप्त होती है, तो मुझे अलग करने की आवश्यकता होती है और कस्टम एक है या एक बार में ऐसा करने का कोई तरीका है? निर्माण के लिए एक नया उपयोगकर्ता?
मार्टिन ट्रिगाक्स

5
यह उत्तर और टिप्पणियां पुरानी हो गई हैं जैसे AUTH_PROFILE_MODULE को हटा दिया गया है,User
उपयोगकर्ता

196

खैर, 2008 के बाद से कुछ समय बीत गया और कुछ नए उत्तर के लिए समय आ गया। Django 1.5 के बाद से आप कस्टम उपयोगकर्ता वर्ग बना पाएंगे। दरअसल, जिस समय मैं यह लिख रहा हूं, यह पहले से ही मास्टर में विलय हो चुका है, इसलिए आप इसे आजमा सकते हैं।

डॉक्स में इसके बारे में कुछ जानकारी है या यदि आप इसे कमिट करना चाहते हैं तो इस कमिट में

आपको केवल AUTH_USER_MODELकस्टम उपयोगकर्ता वर्ग के पथ के साथ सेटिंग में जोड़ना है, जो या तो AbstractBaseUser(अधिक अनुकूलन संस्करण) या AbstractUser(अधिक या कम पुराना उपयोगकर्ता वर्ग जिसे आप बढ़ा सकते हैं) तक फैला हुआ है।

उन लोगों के लिए जो क्लिक करने के लिए आलसी हैं, यहां कोड उदाहरण ( डॉक्स से लिया गया ):

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 फ़ंक्शन उपयोगकर्ता नाम को संग्रहीत करने के लिए प्रतीत नहीं होता है, तो कैसे ?!
ओर्का

6
क्योंकि इस उदाहरण में, emailउपयोगकर्ता नाम है।
ओन्ड्रेज स्लिंटक

5
आपको इसे स्वीकार unique=Trueकरने के लिए ईमेल फ़ील्ड में जोड़ना USERNAME_FIELDहोगा
रिचर्ड डे विट

नमस्ते, मैं कस्टम उपयोगकर्ता बनाने की कोशिश कर रहा था जैसा आपने कहा था, लेकिन कस्टम उपयोगकर्ता ईमेल के ईमेल का उपयोग करके लॉगिन करने में सक्षम नहीं हो सका। क्या आप यह कहना बुरा नहीं मानेंगे कि क्यों?
लियोनेल

मैं वास्तव में विशिष्टताओं के बिना आपकी मदद नहीं कर सकता। यदि आपने नया प्रश्न बनाया है तो बेहतर होगा।
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_auth, तो मैं OneToOne संबंध का उपयोग करने की सलाह देता हूं। इस विधि का उपयोग न करें या यह आपके माइग्रेशन को गड़बड़ कर देगा।
निम्मो

@ निम्मो: क्या आप संदर्भ को विस्तृत या उद्धृत कर सकते हैं
उपयोगकर्ता

@ बफ़र, यह एक लंबे समय से पहले था, लेकिन मुझे लगता है कि मैंने django_social_authप्लगइन को संयोजित करने और AUTH_USER_MODEL को सामाजिक मौखिक उपयोगकर्ता को परिभाषित करने की कोशिश की । फिर, जब मैं प्रबंधित करता था, तो मैं इसे अपने एप में गड़बड़ कर देता था। जब इसके बजाय मैंने यहाँ वर्णित 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
मुझे स्कॉट के दृष्टिकोण को बहुत बेहतर लगता है, सीधे मॉडल के बजाय उपयोगकर्ता ऑब्जेक्ट की विरासत के आधार पर। क्या कोई कह सकता है कि यह दृष्टिकोण बुद्धिमान नहीं है?
BozoJoe

1
@BozoJoe - मैं सिर्फ डंप डेटा आयात करने वाले इस मुद्दे में भाग गया, जो इस पद्धति का उपयोग करने का एक परिणाम प्रतीत होता है: stackoverflow.com/questions/8840068/…
बेन रेजेन्सपेन

15

जब आप उपयोगकर्ता को Django पोस्ट सेव सिग्नल का उपयोग करके बनाया जाता है, तो आप प्रत्येक बार एक नई प्रविष्टि बनाकर उपयोगकर्ता प्रोफ़ाइल का विस्तार कर सकते हैं

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 ) का उपयोग कर सकते हैं । यह यूजरप्रोफाइल मॉडल में परिभाषित सभी क्षेत्रों के साथ एक उपयोगकर्ता ऐड फॉर्म बनाएगा।

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..any संकेत में एक साथ कैसे जोड़ा जाए?
साल

@sal जोड़ा गया यूआरएल उदाहरण अब आप देख सकते हैं
अतुल यादव

धन्यवाद!!। इससे मुझे बहुत सहायता प्राप्त हुई। अच्छा उदाहरण
सनी चौधरी

@AtulYadav .. Django का संस्करण क्या है जो आपने उपयोग किया है?
रिदो

8

प्रो की तरह Django उपयोगकर्ता मॉडल (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
किया हुआ। मैं uderstand क्यों नहीं -1। इस मामले में एक डाउनवोट से बेहतर संपादन।
मासिमो वेरोलो

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

वर्तमान में Django 2.2 के रूप में, एक नया प्रोजेक्ट शुरू करते समय अनुशंसित तरीका है कि एक कस्टम उपयोगकर्ता मॉडल बनाया जाए जो AbstractUser से विरासत में मिले, फिर AUTH_USER_MODEL को मॉडल पर इंगित करें।

स्रोत: https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#use-a-custom-user-model-when-starting-a-project


0

सिंपल और इफेक्टिव अप्रोच है माॅडल

from django.contrib.auth.models import User
class CustomUser(User):
     profile_pic = models.ImageField(upload_to='...')
     other_field = models.CharField()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.