surroundings

Python 3.5.1

django 1.9.1

Foreword

Today, with django write web platform, the first thought that comes django authentication session provides even better, since there are the wheels, and we do not need their own built.

Extension of method django user:

A rewrite user, will register a new user to the admin, but also to rewrite certification

Second, inherited user, expand (remember to set the settings in AUTH_USER_MODEL

AUTH_USER_MODEL = "myapp.NewUser"
 

)

2.1 class inherits AbstractUser

If you are satisfied with django comes with the User model, and hope to add additional field, you can extend AbstractUser class (this paper is to implement this method)

The new django User class supports email, you can also use email as a user login

2.2 class inherits AbstractBaseUser

AbstractBaseUser contains only three field: password, last_login and is_active this is your own highly customized things they need.

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)
 

Three, profile way to expand, but from the beginning to give up such an approach django1.6

Fourth, the online method to find, do not change the source code, without the new table, extended 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'电话号码')
 

 

Explain a little this code: ProfileBase is a custom metaclass inherits from types.ClassTypewhich ProfileUser a base class, its metaclass is ProfileBase, but what we really ExtraInfo custom field type, reason why the base class ProfileUser and ExtraInfo separately, for ease of reference ProfileUser elsewhere, for custom extensions. Simply put, when you see the interpreter in the definition of a subclass ProfileUser class and metaclass ProfileUser class is ProfileBase, so ExtraInfo metaclass is ProfileBase, in the subclass definition ProfileUser when it performs yuan class ProfileBase the new code, and is defined in class (name of the base class, class attributes) passed as a parameter to the new, name here is the name of the class ExtraInfo, attrs medium contains your newly added field, by User.add_to_classthe the new field is added to the User, in order to be able to show up in the admin, add it to the UserAdmin.fieldsetsmiddle, so you can edit this field in the background, of course, you can also add to ist_display, so that it appears in the list.

If you have any other app would also like to add to the User Model in the field or method, as long as all subclasses ProfileUser by category, and then use declarative syntax to define all other work has metaclass help you to complete. This is also the inner workings of all django model, you can use this method to extend any model.

Reprinted Source: http://www.opscoder.info/extend_user.html

demand

Register Login have ready-made code that comes with the User field primarily only (email, username, password), it is necessary to expand User, we need to increase the field

 

code show as below:

 

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',)
 

Stepped pit:

1, after the extended user table, to add in settings.py

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

2, authentication settings in the background to add, particularly remember a comma, otherwise an error

Certified background without being given

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

The error did not add a comma

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('/')
 

 

Stepped pit:

1, when landing with built-in authentication module always reported none

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

View source found to be check_password approach is to check with a hash, password written before the registration is

user.password=password
 

The wording is expressly storage, we need to change the wording of the password storage

user.set_password(password)