中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

django 擴展User

發布時間:2020-06-19 10:04:09 來源:網絡 閱讀:8959 作者:戰狐 欄目:開發技術

環境

Python 3.5.1

django 1.9.1

前言

今天用django寫web平臺,第一時間想到django自帶的認證,連session都提供好了,既然有輪子了,我們就不需要自己造了。

擴展django user的部分方法:

一、重寫user,將新的user注冊到admin,還要重寫認證

二、繼承user,進行擴展(記得在settings中設置AUTH_USER_MODEL

AUTH_USER_MODEL = "myapp.NewUser"

)

2.1 繼承AbstractUser類

如果你對django自帶的User model感到滿意, 又希望增加額外的field的話, 你可以擴展AbstractUser類(本文就是這種方法實現)

新的django User類支持email,也可以用email作為用戶登陸

2.2 繼承AbstractBaseUser類

AbstractBaseUser中只含有3個field: password, last_login和is_active. 這個就是你自己高度定制自己需要的東西

model.py

# class UserManager(BaseUserManager):
#     # def create_user(self, email, username, mobile, password=None):
#     def create_user(self, email, username, mobile, password=None, **kwargs):
#         """通過郵箱,密碼,手機號創建用戶"""
#         if not email:
#             raise ValueError(u'用戶必須要有郵箱')
#
#         user = self.model(
#             email = self.normalize_email(email),
#             username = username,
#             mobile = mobile,
#         )
#
#         user.set_password(password)
#         if kwargs:
#             if kwargs.get('qq', None): user.qq = kwargs['qq']                                          #qq號
#             if kwargs.get('is_active', None): user.is_active = kwargs['is_active']                  #是否激活
#             if kwargs.get('wechat', None): user.wechat = kwargs['wechat']                            #微信號
#             if kwargs.get('refuserid', None): user.refuserid = kwargs['refuserid']                  #推薦人ID
#             if kwargs.get('vevideo', None): user.vevideo = kwargs['vevideo']                         #視頻認證
#             if kwargs.get('identicard', None): user.identicard = kwargs['identicard']               #×××認證
#             if kwargs.get('type', None): user.type = kwargs['type']
#         user.save(using=self._db)
#         return user
#
#     def create_superuser(self,email, username, password,mobile):
#         user = self.create_user(email,
#                             username=username,
#                             password=password,
#                             mobile = mobile,
#         )
#         user.is_admin = True
#         user.save(using=self.db)
#         return user
#
# class User(AbstractBaseUser, PermissionsMixin):
#     """擴展User"""
#     email = models.EmailField(verbose_name='Email', max_length=255, unique=True, db_index=True)
#     username = models.CharField(max_length=50)
#     qq = models.CharField(max_length=16)
#     mobile = models.CharField(max_length=11)
#     wechat = models.CharField(max_length=100)
#     refuserid = models.CharField(max_length=20)
#     vevideo = models.BooleanField(default=False)
#     identicard = models.BooleanField(default=False)
#     created_at = models.DateTimeField(auto_now_add=True)
#     type = models.CharField(u'用戶類型', default='0', max_length=1)
#
#     is_active = models.BooleanField(default=True)
#     is_admin = models.BooleanField(default=False)
#
#     objects = UserManager()
#
#     USERNAME_FIELD = 'email'
#     REQUIRED_FIELDS = ['mobile']
#
#     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
#
#     #On python 2: def __unicode__(self):
#     def __str__(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
#

admin.py

# class UserCreationForm(forms.ModelForm):
#     password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
#     password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
#
#     class Meta:
#         model = MyUser
#         fields = ('email', 'mobile')
#
#     def clean_password2(self):
#         # Check that the two password entries match
#         password1 = self.cleaned_data.get("password1")
#         password2 = self.cleaned_data.get("password2")
#         if password1 and password2 and password1 != password2:
#             raise forms.ValidationError("Passwords don't match")
#         return password2
#
#     def save(self, commit=True):
#         # Save the provided password in hashed format
#         user = super(UserCreationForm, self).save(commit=False)
#         user.set_password(self.cleaned_data["password1"])
#         if commit:
#             user.save()
#         return user
#
#
# class UserChangeForm(forms.ModelForm):
#     password = ReadOnlyPasswordHashField()
#
#     class Meta:
#         model = MyUser
#         fields = ('email', 'password', 'mobile', 'is_active', 'is_admin')
#
#     def clean_password(self):
#         return self.initial['password']
#
# class UserAdmin(BaseUserAdmin):
#     form = UserChangeForm
#     add_form = UserCreationForm
#     list_display = ('email', 'mobile','is_admin')
#     list_filter = ('is_admin',)
#     fieldsets = (
#         (None, {'fields': ('email', 'password')}),
#         ('Personal info', {'fields': ('mobile',)}),
#         ('Permissions', {'fields': ('is_admin',)}),
#     )
#     add_fieldsets = (
#         (None, {
#             'classes': ('wide',),
#             'fields' :('email','mobile', 'password1', 'password2')}
#         ),
#     )
#     search_fields = ('email',)
#     ordering = ('email',)
#     filter_horizontal = ()
#
# admin.site.register(MyUser,UserAdmin)
# admin.site.unregister(Group)

三、profile方式擴展,但是從django1.6開始就放棄這種寫法

四、網上找的方法,不改源碼、不加新表,擴展user

from django.db import models  from django.contrib.auth.models import User  from django.contrib.auth.admin import UserAdmin  import datetime  class ProfileBase(type):  
    def __new__(cls, name, bases, attrs):  #構造器,(名字,基類,類屬性)
        module = attrs.pop('__module__')  
        parents = [b for b in bases if isinstance(b, ProfileBase)]  
        if parents:  
            fields = []  
            for obj_name, obj in attrs.items():  
                if isinstance(obj, models.Field): fields.append(obj_name)  
                User.add_to_class(obj_name, obj)       ####最重要的步驟
            UserAdmin.fieldsets = list(UserAdmin.fieldsets)  
            UserAdmin.fieldsets.append((name, {'fields': fields}))  
        return super(ProfileBase, cls).__new__(cls, name, bases, attrs)  class ProfileUser(object):  
    __metaclass__ = ProfileBase  class ExtraInfo(ProfileUser):  
    phone_number= models.CharField(max_length = 20, verbose_name=u'電話號碼')

稍微解釋一下這段代碼: ProfileBase是自定義的一個元類,繼承自types.ClassType,其中ProfileUser為一個基類,其元類為ProfileBase,而ExtraInfo才是我們真正自定義字段的類,之所以把基類ProfileUser和ExtraInfo分開,是為了便于在其他地方引用ProfileUser,進行自定義擴展。簡單說來,當解釋器看到你在定義一個ProfileUser類的子類,而ProfileUser類的元類是ProfileBase,所以ExtraInfo的元類也是ProfileBase,在定義ProfileUser的子類的時候,它就會執行元類ProfileBase中的new中代碼,并且將正在定義的類的(名字,基類,類屬性)作為參數傳遞給new,這里的name就是類名ExtraInfo,attrs中則包含你新加的字段,通過User.add_to_class把新的字段加入到User中,為了能在admin中顯示出來,把它加入到UserAdmin.fieldsets中,這樣就能在后臺編輯這個這個字段,當然,你也可以加入到ist_display,使之在列表中顯示。

如果你有其他app也想往User Model中加field或方法,都只要通過子類ProfileUser類,然后使用聲明語法進行定義即可,所有其他工作都有元類幫你完成。這也是所有django的model的內部工作,你可以用此方法擴展任何model。

轉載出處:http://www.opscoder.info/extend_user.html

需求

注冊登錄都有現成的代碼,主要是自帶的User字段只有(email,username,password),所以需要擴展User,來增加自己需要的字段


代碼如下:


model.py

#coding:utf8
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.encoding import python_2_unicode_compatible

# Create your models here.
@python_2_unicode_compatible        
"""是django內置的兼容python2和python3的unicode語法的一個裝飾器
只是針對 __str__ 方法而用的,__str__方法是為了后臺管理(admin)和django shell的顯示,Meta類也是為后臺顯示服務的
"""
class MyUser(AbstractUser):
    qq = models.CharField(u'qq號', max_length=16)
    weChat =models.CharField(u'微信賬號', max_length=100)
    mobile =models.CharField(u'手機號', primary_key=True, max_length=11)
    identicard =models.BooleanField(u'×××認證', default=False)                             #默認是0,未認證, 1:×××認證, 2:視頻認證
    refuserid = models.CharField(u'推薦人ID', max_length=20)
    Level = models.CharField(u'用戶等級', default='0', max_length=2)                        #默認是0,用戶等級0-9
    vevideo = models.BooleanField(u'視頻認證', default=False)                      #默認是0,未認證。 1:已認證
    Type =models.CharField(u'用戶類型', default='0', max_length=1)                          #默認是0,未認證, 1:刷手 2:商家

    def __str__(self):
        return self.username


settings.py

AUTH_USER_MODEL = 'appname.MyUser'
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)

踩過的坑:

1、擴展user表后,要在settings.py 添加

AUTH_USER_MODEL = 'appname.擴展user的class name'

2、認證后臺要在settings添加,尤其記得加逗號,否則報錯

認證后臺不加的報錯

Django-AttributeError 'User' object has no attribute 'backend'

沒加逗號的報錯

ImportError: a doesn't look like a module path


form.py

#coding:utf-8
from django import forms

#注冊表單
class RegisterForm(forms.Form):
    username = forms.CharField(label='用戶名',max_length=100)
    password = forms.CharField(label='密碼',widget=forms.PasswordInput())
    password2 = forms.CharField(label='確認密碼',widget=forms.PasswordInput())
    mobile = forms.CharField(label='手機號', max_length=11)
    email = forms.EmailField()
    qq = forms.CharField(label='QQ號', max_length=16)
    type = forms.ChoiceField(label='注冊類型', choices=(('buyer','買家'),('saler','商家')))

    def clean(self):
        if not self.is_valid():
            raise forms.ValidationError('所有項都為必填項')
        elif self.cleaned_data['password2'] != self.cleaned_data['password']:
            raise forms.ValidationError('兩次輸入密碼不一致')
        else:
            cleaned_data = super(RegisterForm, self).clean()
        return cleaned_data

#登陸表單
class LoginForm(forms.Form):
    username = forms.CharField(label='用戶名',widget=forms.TextInput(attrs={"placeholder": "用戶名", "required": "required",}),
                               max_length=50, error_messages={"required": "username不能為空",})
    password = forms.CharField(label='密碼',widget=forms.PasswordInput(attrs={"placeholder": "密碼", "required": "required",}),
                               max_length=20, error_messages={"required": "password不能為空",})


views.py

from django.shortcuts import render,render_to_response
from .models import MyUser
from django.http import HttpResponse,HttpResponseRedirect
from django.template import RequestContext
import time
from .myclass import form
from django.template import RequestContext
from django.contrib.auth import authenticate,login,logout

#注冊
def register(request):
    error = []
    # if request.method == 'GET':
    #     return render_to_response('register.html',{'uf':uf})
    if request.method == 'POST':
        uf = form.RegisterForm(request.POST)
        if uf.is_valid():
            username = uf.cleaned_data['username']
            password = uf.cleaned_data['password']
            password2 = uf.cleaned_data['password2']
            qq = uf.cleaned_data['qq']
            email = uf.cleaned_data['email']
            mobile = uf.cleaned_data['mobile']
            type = uf.cleaned_data['type']
            if not MyUser.objects.all().filter(username=username):
                user = MyUser()
                user.username = username
                user.set_password(password)
                user.qq = qq
                user.email = email
                user.mobile = mobile
                user.type = type
                user.save()
                return render_to_response('member.html', {'username': username})
    else:
        uf = form.RegisterForm()
    return render_to_response('register.html',{'uf':uf,'error':error})
 
#登陸    
def do_login(request):
    if request.method =='POST':
        lf = form.LoginForm(request.POST)
        if lf.is_valid():
            username = lf.cleaned_data['username']
            password = lf.cleaned_data['password']
            user = authenticate(username=username, password=password)               #django自帶auth驗證用戶名密碼
            if user is not None:                                                  #判斷用戶是否存在
                if user.is_active:                                                  #判斷用戶是否激活
                    login(request,user)                                                 #用戶信息驗證成功后把登陸信息寫入session
                    return render_to_response("member.html", {'username':username})
                else:
                    return render_to_response('disable.html',{'username':username})
            else:
                return HttpResponse("無效的用戶名或者密碼!!!")
    else:
        lf = form.LoginForm()
    return render_to_response('index.html',{'lf':lf})
    
#退出
def do_logout(request):
    logout(request)
    return HttpResponseRedirect('/')


踩過的坑:

1、登陸的時候用自帶的認證模塊總是報none

user = authenticate(username=username, password=password)

查看源碼發現是check_password的方法是用hash進行校驗,之前注冊的password寫法是

user.password=password

這種寫法是明文入庫,需要更改密碼的入庫寫法

user.set_password(password)


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

靖西县| 方城县| 镇沅| 永泰县| 乐至县| 自治县| 睢宁县| 乌审旗| 灌阳县| 保定市| 泾源县| 丹寨县| 红安县| 微博| 名山县| 浙江省| 刚察县| 阳城县| 河北省| 台中县| 论坛| 杂多县| 松桃| 广西| 阜平县| 琼结县| 奉节县| 肇庆市| 娄底市| 泽州县| 革吉县| 茌平县| 陵水| 灵宝市| 石泉县| 贺州市| 栖霞市| 承德县| 广水市| 综艺| 珲春市|