User模型擴展和自定義

參考以下:css

django文檔參考html

django signal使用總結html5

django 信號註冊python

django信號問題1數據庫

django oneTooneFileddjango

 

 
 

1. django 自定義用戶user模型的三種方法

 

1.1 建立基於User 的proxy model,就是使用代理模型

1.2 使用abstractuser擴充fields

試驗過,可是老是有報錯,應該是哪裏設置的問題。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'

  

1.3.使用一對一關係將相關的模型一個個聯繫起來,擴充原來的User模型

這很像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)

 

1.4.繼承abstractbaseuser來替代原來的User模型

只有當你對usermodel裏面的默認字段不滿的時候纔要使用,這個方法只保留了passwork,last_login,is_active三個字段。

參考官方文檔:
https://docs.djangoproject.com/en/1.7/topics/auth/customizing/

 

 

我的認爲在個人建站場景中,第二種最合適.正在測試是否能夠用抽象類簡化模型.待續...

以上3種方法各有優劣,你們根據本身的需求,自由選擇吧。

 

2.  OneToOneFiled的具體實現記錄

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>-->
相關文章
相關標籤/搜索