参考如下:
django文档参考
django signal使用总结
django 信号注册
django信号问题1
django oneTooneFiled
User
的proxy model,就是使用代理模型试验过,但是总是有报错,应该是哪里设置的问题。
代码如下:
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之前的方式.很适用于创建第三方扩充包的场景,松耦合,不会破坏之前项目的结构.
需要此方法的场景:
- 在自己的django prj下,希望有多重user拥有各自很不相同的字段.或许希望有些用户组合起来一些用户的类型字段,并且希望能在模型层面上解决这些问题.
例子如下:
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
"zh-CN"> "utf-8"> "X-UA-Compatible" cOntent="IE=edge"> "viewport" cOntent="> "description" cOntent=""> "author" cOntent=""> "icon" href="../static/favicon.ico"> "https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> "../static/css/ie10-viewport-bug-workaround.css" rel="stylesheet"> "../static/css/signin.css" rel="stylesheet">class="container"> class="form-signin" action="" method="post"> {% csrf_token %}class="form-signin-heading">Please sign in
{{form.username.errors}} {{form.username.lable_tag}} {{form.username}} {{form.password.errors}} {{form.password.lable_tag}} {{form.password}}class="checkbox">{{msg}}