參考以下:css
django文檔參考html
django signal使用總結html5
django 信號註冊python
django信號問題1數據庫
django oneTooneFileddjango
User
的proxy model,就是使用代理模型試驗過,可是老是有報錯,應該是哪裏設置的問題。bootstrap
複製代碼 代碼以下:segmentfault
profiles/models.py from django.db import models from django.contrib.auth.models import AbstractUser from django.utils.translation import ugettext_lazy as _ # Create your models here. class KarmaUser(AbstractUser): karma = models.PositiveIntegerField(_("karma"),default=0,blank=True) settings.py AUTH_USER_MODEL = 'profiles.KarmaUser'
這很像django 1.5以前的方式.很適用於建立第三方擴充包的場景,鬆耦合,不會破壞以前項目的結構.app
須要此方法的場景:
- 在本身的django prj下,但願有多重user擁有各自很不相同的字段.或許但願有些用戶組合起來一些用戶的類型字段,而且但願能在模型層面上解決這些問題.
例子以下:oop
profiles/models.py
複製代碼 代碼以下:
from django.conf import settings from django.db import models from flavors.models import Flavor class EaterProfile(models.Model): # 默認用戶資料 user = models.OneToOneField(settings.AUTH_USER_MODEL) favorite_ice_cream = models.ForeignKey(Flavor,null=True,blank=True) class ScooperProfile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL) scoops_scooped = models.IntegerField(default=0) class InventorProfile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL) flavors_invented = models.ManyToManyField(Flavor,null=True,blank=True)
只有當你對usermodel裏面的默認字段不滿的時候纔要使用,這個方法只保留了passwork,last_login,is_active三個字段。
參考官方文檔:
https://docs.djangoproject.com/en/1.7/topics/auth/customizing/
我的認爲在個人建站場景中,第二種最合適.正在測試是否能夠用抽象類簡化模型.待續...
以上3種方法各有優劣,你們根據本身的需求,自由選擇吧。
1. 需求: 爲了防止暴力破解,要求玩家連續登陸5次錯誤以後賬號鎖定10分鐘(10分鐘後自動解除鎖定)。管理員能夠手動解除鎖定。用戶登陸成功後錯誤次數清零。
2. 作好的登陸app目錄以下:
3. 設計數據庫 loginapp/models.py以下:
#-*- encoding:utf-8 -*-
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import User
from django.db import models
import datetime
import django.utils.timezone as timezone
class Userotherstatus(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE)
is_freezed=models.BooleanField(default=False,help_text=u"賬號是否被凍結")
freezed_time=models.DateTimeField(null=True,blank=True,help_text=u"賬號凍結的時間點")
pass_errnum=models.IntegerField(default=0,help_text=u"密碼已經錯誤次數")
注意:經過 python manage.py migrate將models應用導數據庫後,建立用戶事後,User模型一對一的Userotherstatus模型對應的數據庫表裏面沒有數據。
解決辦法使用 django signal。當咱們建立和更新用戶實例時,Userotherstatus模塊也會被自動建立和更新。
4. signal 實現以下:
參考: https://blog.csdn.net/qq_32506555/article/details/53219036
參考: https://yiyibooks.cn/xx/Django_1.11.6/topics/signals.html
loginapp/signals.py
#-*- encoding: utf-8 -*- from django.db.models.signals import post_save from django.contrib.auth.models import User from .models import Userotherstatus from django.dispatch import receiver @receiver(post_save, sender=User) def creat_user_otherstatus(sender,instance,created,**kwargs): print "use signal creat" if created: Userotherstatus.objects.create(user=instance) @receiver(post_save, sender=User) def save_user_otherstatus(sender, instance, **kwargs): print (" use signal save") instance.userotherstatus.save() #
signal 信號註冊:
loginapp/apps.py
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.apps import AppConfig class LoginappConfig(AppConfig): name = 'loginapp' def ready(self): import loginapp.signals
loginapp/__init__.py
default_app_config = 'loginapp.apps.LoginappConfig'
5. 後臺views的實現 loginapp/views.py:
思路:
賬號是否鎖定》鎖定》判斷是否過了鎖定時間》是》解鎖而且錯誤次數設置爲0
否》提示處於鎖定狀態
》沒鎖定 》判斷錯誤次數
》都不知足進行登陸驗證
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect from django.contrib.auth import authenticate,login,logout from django.contrib.auth.models import User # from django.contrib.auth.models import BaseUserManager # from django.contrib.auth.hashers import make_password, check_password # from django.views.generic.base import View import datetime from LoginForm import MyLoginForm from loginapp.models import Userotherstatus from django.views.decorators.csrf import csrf_protect,requires_csrf_token # Create your views here. @requires_csrf_token @csrf_protect def MyLogin(request): lock_time=60 pass_error_limit=5 form = MyLoginForm() if request.method=="POST": print request.path #驗證表單 form = MyLoginForm(request.POST) if form.is_valid(): username=request.POST["username"] password=request.POST["password"] #驗證用戶 try: user_id=User.objects.get(username=username).id print 1111111111111111111111 except Exception: return render(request,'loginapp/login.html',{'form':form,'msg':"用戶不存在"}) freezed_time=Userotherstatus.objects.get(user_id=user_id).freezed_time pass_errornum=Userotherstatus.objects.get(user_id=user_id).pass_errnum is_freezed=Userotherstatus.objects.get(user_id=user_id).is_freezed print(freezed_time,pass_errornum,is_freezed) if is_freezed==True and freezed_time: print 2222222222222222222222 print ((datetime.datetime.now() - (freezed_time.replace(tzinfo=None))).total_seconds()) if (datetime.datetime.now()-(freezed_time.replace(tzinfo=None))).total_seconds()>lock_time: print("重置") Userotherstatus.objects.filter(user_id=user_id).update(is_freezed=False,pass_errnum=0) # Userotherstatus.objects.filter(user_id=user_id).update() user=authenticate(username=username,password=password) if user is not None and user.is_active: login(request,user) User.last_login=datetime.datetime.now() return HttpResponse("登陸成功") else : return render(request,'loginapp/login.html', {'form':form,'msg':'賬號鎖定中,請稍後再嘗試,須要解鎖請聯繫管理員!'}) if pass_errornum>=5: print 33333333333333333 Userotherstatus.objects.filter(user_id=user_id).update(is_freezed=True,pass_errnum=0) Userotherstatus.objects.filter(user_id=user_id).update(freezed_time=datetime.datetime.now()) return render(request,'loginapp/login.html', {'form':form,'msg':"密碼連續錯誤5次,賬號已經被鎖定"}) else: user=authenticate(username=username,password=password) if user is not None and user.is_active: login(request, user) User.last_login = datetime.datetime.now() Userotherstatus.objects.filter(user_id=user_id).update(is_freezed=False,pass_errnum=0) # Userotherstatus.objects.filter(user_id=user_id).update() return HttpResponse("登陸成功") else: print 4444444444444444444444 Userotherstatus.objects.filter(user_id=user_id).update(pass_errnum=(int(pass_errornum)+1)) return render(request, 'loginapp/login.html', {'form': form}) else: return render(request,'loginapp/login.html', {'form':form})
6. 附上 表單 loginapp/LoginForm.py
#-*- encoding: utf-8 -*- from django import forms class MyLoginForm(forms.Form): username=forms.CharField(label="inputUser", max_length=20, error_messages={'required':"請輸入用戶名"}, widget=forms.TextInput( attrs={ 'placeholder':"User Name", 'required':'True', 'class':'form-control' }) ) password=forms.CharField(label="inputPassword", max_length=100, error_messages={'required':"請輸入密碼"}, widget=forms.PasswordInput( attrs={ 'placeholder': "Password", 'required':"True", 'class':'form-control', }) )
7. 附上 login.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! --> <meta name="description" content=""> <meta name="author" content=""> <link rel="icon" href="../static/favicon.ico"> <title>Signin Page</title> <!-- Bootstrap core CSS --> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <link href="../static/css/ie10-viewport-bug-workaround.css" rel="stylesheet"> <!-- Custom styles for this template --> <link href="../static/css/signin.css" rel="stylesheet"> <!-- Just for debugging purposes. Don't actually copy these 2 lines! --> <!--[if lt IE 9]><script src="../static/js/ie8-responsive-file-warning.js"></script><![endif]--> <script src="../static/js/ie-emulation-modes-warning.js"></script> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <form class="form-signin" action="" method="post"> {% csrf_token %} <h2 class="form-signin-heading">Please sign in</h2> {{form.username.errors}} {{form.username.lable_tag}} {{form.username}} {{form.password.errors}} {{form.password.lable_tag}} {{form.password}} <div class="checkbox"> <label> <input type="checkbox" value="remember-me"> Remember me </label> </div> <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> {{msg}} </form> </div> <!-- /container --> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <script src="../static/js/ie10-viewport-bug-workaround.js"></script> </body> </html> <!--<form class="form-signin" action="" method="post">--> <!--<h2 class="form-signin-heading">Please sign in</h2>--> <!--<label for="inputUser" class="sr-only">User</label>--> <!--<input type="text" id="inputUser" class="form-control" placeholder="User Name" required autofocus>--> <!--<label for="inputPassword" class="sr-only">Password</label>--> <!--<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>--> <!--<div class="checkbox">--> <!--<label>--> <!--<input type="checkbox" value="remember-me"> Remember me--> <!--</label>--> <!--</div>--> <!--<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>--> <!--</form>-->