Python CRM項目八


自定義用戶認證

目的:實現Django自定義的認證系統,在生產環境都是根據此代碼進行定制的

步驟:

  1.在settings文件中配置要使用的類

                 #命名規則 app名稱.類名      
AUTH_USER_MODEL = 'crm.UserProfile'

  2.在crm app下的models文件中加入Django官方的用戶認證

from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser,PermissionsMixin
)
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
class UserProfileManager(BaseUserManager): def create_user(self, email, name, password=None):     #創建用戶根據UserProfile中的字段,輸入 if not email: raise ValueError('Users must have an email address') user = self.model( email=self.normalize_email(email), name=name, ) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, name, password):     #創建超級用戶根據UserProfile中的字段,輸入 user = self.create_user( email, password=password, name=name, ) user.is_admin = True user.save(using=self._db) return user class UserProfile(AbstractBaseUser,PermissionsMixin):
#使用Django自帶的登錄系統,可以自定義一些字段,例如郵箱,密碼,用戶名 email
= models.EmailField( verbose_name='email address', max_length=255, unique=True, ) password = models.CharField(_('password'), max_length=128,help_text = mark_safe('<a href="password/">修改密碼</a>')) name = models.CharField(max_length=32) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False)   
  #在創建用戶的時候調用該方法進行用戶的創建 objects
= UserProfileManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['name'] 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 def __str__(self): # __unicode__ on Python 2 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: active users are staff return self.is_active class Meta: verbose_name_plural = '用戶'

  3.在crm app下的admin中

from django import forms
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from crm.models import UserProfile

class UserCreationForm(forms.ModelForm):
  #在Django Admin頁面中用戶創建的表單展示
"""A form for creating new users. Includes all the required fields, plus a repeated password.""" password1 = forms.CharField(label='Password', widget=forms.PasswordInput) password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) class Meta:
#展示的model對象和字段 model
= UserProfile fields = ('email', 'name') 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):
#在Django Admin頁面中用戶修改的表單展示
"""A form for updating users. Includes all the fields on the user, but replaces the password field with admin's password hash display field. """ password = ReadOnlyPasswordHashField() class Meta:
     #展示的model對象和字段   model
= UserProfile fields = ('email', 'password', 'name', 'is_active', 'is_admin') def clean_password(self): # Regardless of what the user provides, return the initial value. # This is done here, rather than on the field, because the # field does not have access to the initial value return self.initial["password"] class UserProfileAdmin(BaseUserAdmin):
#在在Django Admin頁面中配置的admin_class
# The forms to add and change user instances form = UserChangeForm #調用修改用戶的表單 add_form = UserCreationForm #調用創建用戶的表單 # The fields to be used in displaying the User model. # These override the definitions on the base UserAdmin # that reference specific fields on auth.User. list_display = ('email', 'name', 'is_admin') list_filter = ('is_admin',) fieldsets = ( (None, {'fields': ('email', 'password')}), ('Personal info', {'fields': ('name',)}), ('Permissions', {'fields': ('is_admin','is_active','user_permissions',)}), ) # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin # overrides get_fieldsets to use this attribute when creating a user. add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ('email', 'name', 'password1', 'password2')} ), ) search_fields = ('email',) ordering = ('email',) filter_horizontal = ('groups','user_permissions') admin.site.unregister(Group)
#把models對象中的model對象和admin_class對象組合起來 admin.site.register(models.UserProfile,UserProfileAdmin)

  4.在king_admin中實現修改密碼的功能

 在king_admin的urls.py中配置

url(r'^(\w+)/(\w+)/(\d+)/change/password/$',views.password_reset,name='password_reset'),

 在king_admin中的king_admin.py中配置

class UserAdmin(BaseAdmin):
    list_display = ['email','name']   #首頁展示的字段
    readonly_fields = ['password',]   #只讀字段 
    modelfrom_exclude_fields = ['last_login','is_superuser','groups','user_permissions']   #不展示的字段

 在views函數中開發該模塊

def password_reset(request,app_name,table_name,obj_id):
    '''動態修改密碼'''
#獲取admin_class類和要修改密碼的對象
admin_class = king_admin.enabled_admins[app_name][table_name] model_obj = admin_class.model.objects.get(id=obj_id) errors = {} if request.method == 'POST':
#獲取前端頁面的兩個值,密碼和新密碼 _password1
= request.POST.get('password1') _password2 = request.POST.get('password2')
#如果兩次密碼相同,並且長度大於5位,則調用父類的方法保存密碼,同時入庫,最后返回到展示頁面
if _password1 == _password2: if len(_password2) > 5: model_obj.set_password(_password1) model_obj.save()
#保存成功則跳轉到展示頁面進行展示
return redirect(request.path.rstrip('password/')) else: errors['invalid_password'] = '密碼長度不足6位' else: errors['invalid_password'] = '兩次密碼不一致' return render(request,'king_admin/password_reset.html',{'model_obj':model_obj})

  5.在forms.py中將不需要展示的字段寫到exclude上

class Meta:
    model = admin_class.model
    fields = '__all__'
    exclude = admin_class.modelfrom_exclude_fields     #排除的字段

  6.前端頁面

  本質上是一個form表達,展示用戶的用戶名,然后用戶填寫密碼和新密碼之后提交到views的方法中進行修改密碼的操作

{% extends 'king_admin/table_index.html' %}

{% block container %}
    <div class="row">
        <div class="panel panel-info">
            <div class="panel-heading">
                <h3 class="panel-title">重置用戶{{ model_obj.name }}密碼</h3>
            </div>
            <div class="panel-body">
                <form method="post" class="form-horizontal">
                    {% csrf_token %}
                    <div class="form-group">
                        <label class="col-sm-1" style="font-weight:normal">
                            用戶名:
                        </label>
                        <div class="col-sm-3">
                            <input class="form-control" type="text" value="{{ model_obj.email }}" disabled>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-1" style="font-weight:normal">
                            密碼:
                        </label>
                        <div class="col-sm-3">
                            <input class="form-control" type="password" name="password1">
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-1" style="font-weight:normal">
                            重復密碼:
                        </label>
                        <div class="col-sm-3">
                            <input class="form-control" type="password" name="password2">
                        </div>
                    </div>
                    <div>
                        <ul style="color:red">
                            {% for k,v in errors.items %}
                                <li>{{ k }}-{{ v }}</li>
                            {% endfor %}
                        </ul>
                    </div>
                    <input type="submit" class="btn btn-info" style="margin-left:110px" value="提交">
                    <input type="reset" class="btn btn-danger" style="margin-left:30px" value="重置">
                </form>
            </div>
        </div>
    </div>
{% endblock %}

 自定義用戶登錄

  目的:利用Django提供的組件,實現自己的用戶認證系統,包括登錄,登出和利用裝飾器實現方法的登錄校驗

  1.在settings文件中配置登錄url的路徑

LOGIN_URL = '/'

  2.在入口的app中配置url

  3.在views中開發登錄,登出和首頁的模塊

from django.shortcuts import render,redirect
from django.contrib.auth import login,authenticate,logout
# Create your views here.

def account_login(request):
    errors = {}
    if request.method == 'POST':
#獲取前端表單的值 _email
= request.POST.get('email') _password = request.POST.get('password') #使用Django自帶的用戶認證 user = authenticate(username=_email,password=_password) if user:
#登錄成功則進行跳轉,如果有next_url則跳轉到下一個頁面,否則跳轉到首頁 login(request,user) next_url
= request.GET.get('next','') if next_url: return redirect(next_url) else: return redirect('/index/') else: errors['error'] = '用戶名密碼不正確' return render(request,'login.html',{'errors':errors}) def account_logout(request):
#用戶登出 logout(request)
return redirect('/account/login/') def index(request): return render(request,'index.html')

  4.在需要登錄校驗的方法上,加上@login_required裝飾器

from django.contrib.auth.decorators import login_required

@login_required
def index(request):
    return render(request, 'king_admin/table_index.html',{'table_list':king_admin.enabled_admins})

  5.前端頁面,form表單以post的方式向后台發送用戶名和密碼,后端的views中相應的方法進行校驗

  {% extends 'base.html' %}

  {% block body %}
      <div class="row">
        <div class="panel panel-info">
            <div class="panel-heading">
                <h3 class="panel-title">登錄CRM系統</h3>
            </div>
            <div class="panel-body ">
              <form class="form-horizontal" method="post">{% csrf_token %}
                <div class="form-group">
                        <label class="col-sm-1" style="font-weight:normal">
                           郵箱:
                        </label>
                        <div class="col-sm-3">
                            <input type="email" name="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
                        </div>
                </div>
                <div class="form-group">
                        <label class="col-sm-1" style="font-weight:normal">
                           密碼:
                        </label>
                        <div class="col-sm-3">
                            <input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>
                        </div>
                </div>
                  {% if errors %}
                      <span style="color: red">{{ errors.error }}</span>
                  {% endif %}
                <button class="btn btn-info" style="margin-left:113px" type="submit">登陸</button>
                <button class="btn btn-danger" type="reset">清空</button>
              </form>
            </div>
        </div>
      </div>

{% endblock %}

  6.在index首頁集成用戶登出同時生成動態的菜單鏈接,點擊跳轉到相應的頁面

  登出

<li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{ request.user.name }}</a>
        <ul class="dropdown-menu" role="menu">
            <li><a href="{% url 'account_logout' %}">注銷</a></li>
        </ul>
</li>

  動態菜單生成

<div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">

              {% for role in request.user.roles.all %}
                {% for menu in role.menus.all %}
                    <li>
{# 如果是絕對路徑的url type=1,直接顯示url的名稱,如果是相對路徑的url type=0,則動態根據url的別名來獲取url #} <a href="{% if menu.url_type == 0 %}{% url menu.url_name %}{% else %}{{ menu.url_name }}{% endif %}">{{ menu.name }}</a> </li> {% endfor %} {% endfor %} </ul> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> {% block page-content %} {% endblock %} </div> </div> </div>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM