zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    POJ2965(The Pilots Brothers' refrigerator)
    POJ1753(Flip Game)
    POJ3253(Fence Repair)
    山东理工大学的训练计划
    loutsScript 常用代码
    《大道至简》读后感
    2019暑第三周
    2019暑第二周
    2019暑第一周
    关于13组作品《TD tree》的使用感想
  • 原文地址:https://www.cnblogs.com/luhuajun/p/7929166.html
Copyright © 2011-2022 走看看