Django之用户管理系统CBV-全新升级(5)

时间过的真快,又接近4个月没更新文章了,不是我闲着,家里事情是真多,时间都给了溜娃还是溜娃,剩余点时间就学习Django的知识,为了打磨好这一篇文章,可费了九牛二虎之力,完成该篇文章。

为了各位读者有较好的UI视觉、有动力去学习和摸索,前端可投入不少时间。毕竟作为一名网工,去搞前端,那还真不是一件容易的事情,你想,Django这个后端知识体系已经够学一阵一阵子的了。

前端有啥学习?HTML、javascrip、jQuery、ajAX、Vue...

后端有啥学习?Django就够了...

前方高能,请看如下效果图...


1.0 效果展示

说明:提前贴出这些图,希望各位看了有动力去学习。虽然django有自带一套用户系统,但是人的审美总是要有的哈,又可以提升下自己的代码水平.

  • 用户列表展示

    user_list.gif
  • 新增用户


  • 更新用户


  • 删除用户

1.1 基础配置

说明:有一些共性的东西,我就提前在这个章节写出来。

  • settings.py 配置
    文件路径:mysite/settings.py

    static文件夹路径:用于存放前端的一些cssjsicon等文件。

    AUTH_USER_MODEL:重写内置的用户管理。

    DATABASES:使用的是mysql数据库,一直用的这个。

    INSTALLED_APPS:新建和注册app,就不多讲了,请看之前的文章。

# mysite/settings.py

INSTALLED_APPS = [
  # 新建的app,注册一下
    'users',  
]

# 定义存放js/cs/img的文件路径
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    (BASE_DIR / 'static'),
)
# 全局声明,使用UserProfile
# 默认是: AUTH_USER_MODEL = 'auth.User'
AUTH_USER_MODEL = 'users.UserProfile'

# 数据库mysql参数配置, 内置有sqlite。
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_db',
        'HOST': '192.168.8.130',
        'USER': '<数据库用户名>',
        'PASSWORD': '<数据库密码>,
        'PORT': 3306,
    }
}
  • 母版配置
    文件路径:mysite/templates/base1.html

    templates目录下新建base1.html文件,作为母版,代码如下所示。

    说明: 母版存放基本cssjs样式, 这样子页面就不用单独加载这些了,切记不要把所有的js或css放在一个html内,避免导致页面加载慢,按需页面加载即可。




{% load  static %}

    

        
        
        
        
        
        
            {% block title %}自动化运维平台{% endblock %}
        

        
        
        
        

        
        

        
        
        

        
        

        
        
        

        
        
        

        
        
        

        {% block css %}{% endblock %}


    
        
        

        
        

{% block page-title %} {% endblock %}

{% block page-content %} {% endblock %}
2021©自动化运维平台
{% block js %}{% endblock %}
  • model配置
    文件路径: mysite/users/models.py

    继承内置用户系统AbstractUser, 内置有usernamepasswordemailis_active等字段,我在此基础上增加了cn_namephonesex, 3个字段属性。

    # mysite/users/models.py
    #!/usr/bin/env python3
    #-*- coding:UTF-8 -*-
    
    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    class Userprofile(AbstractUser):
        SEX_CHOICE = (
            (0, '男'),
            (1, '女'),
        )
        cn_name = models.CharField('中文名', max_length=128)
        phone = models.CharField('手机', max_length=11, null=True, blank=True)
        sex = models.IntegerField(choices=SEX_CHOICE, null=True, blank=True)
    
        class Meta:
            verbose_name = '用户信息'
    
        def __str__(self):
            return self.username
    

    温馨提示:model编写好后,各位记得python manage.py makemigrations userspython manage.py migrate users

  • 路由url配置
    文件路径:mysite/urls.py

    主路由urls:

    # mysite/urls.py
    
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('user/', include('users.urls'))  # 新建
    ]
    

    子路由urls(app为users):

    # mysite/users/urls.py
    
    from django.urls import path, re_path
    from .views import *
    
    app_name = 'users'
    urlpatterns = [
      # 用户查看
        path('userlist/', UserListView.as_view(), name='userlist'),
      # 用户增加
        path('useradd/', UserAddView.as_view(), name='useradd'),
      # 用户编辑
        re_path('useredit/(?P[0-9]+)?/', UserEditView.as_view(), name='useredit'),
      # 用户删除
        re_path('userdel/(?P[0-9]+)?/', UserDelView.as_view(), name='userdel'),
        ]
    
  • 分页
    文件路径:mysite/templates/_paginator.html

    效果是这样子的:


    templates目录下创建_paginator.html,写入如下代码:
    说明:这个分页文件会在userlist.html被调用,这个模板是别人写好的,拿来用即可.

    # mysite/templates/_paginator.html
    
    
    

1.2 用户添加

说明:用户添加的表单使用forms的ModelForm,可以依赖model, 视图则使用generic(通用视图)的CreateView.

  • 创建form.py文件

    #!/usr/bin/env python3
    #-*- coding:UTF-8 -*-
    
    from django import forms
    from django.contrib.auth import get_user_model
    import re
    
    class UserModelForm(forms.ModelForm):
        # 新增确认密码字段,用于两次密码作比较
        # 该字段不用写入数据库
        confirm_password = forms.CharField(required=True)
    
        class Meta:
            # 与model建立了依赖关系,即按照model中的字段类型验证
            model = User
            # 根据model定义的类型,验证列的属性
            fields = ('username', 'cn_name', 'password', 'sex', 'phone')
    
        def clean_phone(self):
            # clean_字段名,该方法用于验证字段,自定义条件
            phone = self.cleaned_data['phone']
            if phone:
                phone_re = re.match("^1[35789][0-9]{9}$", phone)
                # print(phone_re)
                if phone_re:
                    return phone
                else:
                    raise forms.ValidationError("手机号码非法")
            else:
                # ValidationError自定义表单错误
                raise forms.ValidationError("这个字段是必填项")
    
        def clean_confirm_password(self):
            """
            用于比较两次输入的密码
            """
            password = self.cleaned_data.get('password')
            confirm_password = self.cleaned_data.get('confirm_password')
            if password != confirm_password:
                raise forms.ValidationError('两次密码不一致!')
            # return confirm_password
    

    说明:设计成表单,需要单独创建一个form.py,名字自定义,def clean_字段名用于判断表单的字段是否符合设定的要求。

  • 视图配置
    文件路径:mysite/users/views.py

    # mysite/users/views.py
    
    from django.views.generic import CreateView
    from django.contrib.messages.views import SuccessMessageMixin
    from django.contrib.auth import get_user_model
    from .form import UserModelForm
    
    User = get_user_model()
    
    class UserAddView(SuccessMessageMixin, CreateView):
        """
        新增用户
        """
        template_name = 'users/form.html'
        model = User
        form_class = UserModelForm
        success_message = '%(username)s 用户添加成功!'
    
        def get_success_url(self):
            # print(self.request.POST)
            if "_addanother" in self.request.POST:
                return reverse('users:useradd')
            return reverse('users:userlist')
    
        def form_valid(self, form):
            """
            form.cleaned_data:获取表单所有数据
            from.instance:一个用户对象(是一个类)
            """
            password = form.cleaned_data['password']
            form.instance.password = make_password(password)
            # print(form.cleaned_data)
            # print(make_password(password))
            # print(form.instance)
            return super(UserAddView, self).form_valid(form)
    
        def form_invalid(self, form):
            """
            form_invalid方法可以不用写,用于print表单报错.
            """
            # print('form_invalid', form.cleaned_data)
            # print(form.errors.as_json())
            return super(UserAddView, self).form_invalid(form)
    

    参数解读:

    • get_success_url:如果表单正常,return重定向到定义的url。
    • form_valid:如果表单正常,进入该函数,并通过make_password方法生成随机的密文,默认会通过form.save()写入数据库中。
    • form_invalid:如果表单异常,进入该函数(仅用于演示,可不写).
  • 模板配置
    文件路径:mysite/users/templates/form.html

    说明:用户新增和用户修改使用的是同一个模板,里面通过if条件进行区分.

    
    
    {% extends 'base1.html' %}
    
    {% load static %}
    
    {% block title %}
        {% if object %}
            用户更新
        {% else %}
            用户添加
        {% endif %}
    {% endblock %}
    
    {% block page-title %}
        {% if object %}
            用户更新
        {% else %}
            用户添加
        {% endif %}
    {% endblock %}
    
    {% block page-content %}
        
    

    {% if object %}请更新一个用户{% else %}请添加一个用户{% endif %}

    {% if form %}

    {{ form.errors }}

    {% endif %}
    {% if object %} {% endif %}
    {% endblock %}
      *说明:用户更新页面通过if 判断`object`为true,否则就是用户添加页面了*
    
    • 效果图

1.3 用户查看

  • 视图配置

    from django.views.generic import ListView
    from pure_pagination.mixins import PaginationMixin
    from django.contrib.auth import get_user_model
    
    User = get_user_model()
    
    class IsActiveView(View):
        def post(self, request, **kwargs):
            pk = QueryDict(self.request.body).get('pk')
            value =int(QueryDict(self.request.body).get('value'))
            try:
                user = User.objects.filter(id=pk)
                if pk and value == 1:
                    user.update(is_active=1)
                    res = {'code': 0, 'result': '用户激活成功!'}
                elif pk and value == 0:
                    user.update(is_active=0)
                    res = {'code': 0, 'result': '用户禁用成功!'}
                else:
                    res = {'code': 1, 'result': '用户禁用或激活失败!'}
            except:
                res = {'code': 1, 'result': '用户禁用或激活失败!'}
    
            return JsonResponse(res, safe=True)
        
        
    class UserListView(PaginationMixin, ListView):
        """
        查看用户
        """
        template_name = 'users/userlist.html'
        model = User
        context_object_name = 'users'
        paginate_by = 10
        keyword = ''
    
        def get_queryset(self):
            """ 数据过滤, return过滤后的数据 """
            # 获取所有数据
            queryset = super(UserListView, self).get_queryset()
            # print(queryset)
            # 获取搜索框的关键字
            self.keyword = self.request.GET.get('keyword', '')
            if self.keyword:
                if self.keyword == '男':
                    queryset = queryset.filter(sex=0)
                    # print(queryset)
                elif self.keyword == '女':
                    queryset = queryset.filter(sex=1)
                else:
                    queryset = queryset.filter(Q(username__icontains=self.keyword)|
                                               Q(cn_name__icontains=self.keyword)|
                                               Q(is_superuser__icontains=self.keyword)|
                                               Q(phone__icontains=self.keyword)|
                                               Q(is_active__icontains=self.keyword))
            else:
                pass
            return queryset
    
        def get_context_data(self, **kwargs):
            """上下文管理,用于传递给前端渲染的数据"""
            context = super(UserListView, self).get_context_data(**kwargs)
            # print(context)
            context['keyword'] = self.keyword
            return context
    

    参数解读:

    • is_active:缺省为true,is_active=1, is_active=0表示未激活
    • template_name:指定前端渲染的模板(html文件);
    • model:指定模型;
    • context_object_name:自定义上下文对象名称(传递给前端),缺省object_list。
    • paginate_by:分页,每一页10条数据;
    • get_queryset:该方法继承父类获取所有数据,并通过filter + Q过滤数据, 还可以跟order_by()进行排序(升序/降序)。
    • Q:Q对象提供更复杂的查询,如通过 &| 操作符和括号分组,本文使用或关系。
    • get_context_data:该方法用于传给前端渲染的数据,keyword为传给前端搜索框内显示用的。
  • 模板配置

    {% extends 'base1.html' %}
    {% load static %}
    
    {% block title %}
        用户列表
    {% endblock %}
    
    {% block page-title %}
        用户列表
    {% endblock %}
    
    
    {% block css %}
        
        
        
    
    {% endblock %}
    
    {% block page-content %}
    
    {% for user in users %} {% endfor %}
    UID 用户名 管理员 中文名 手机 性别 用户状态 上次登陆时间 操作
    {{ user.id }} {{ user.username }} {% if user.is_superuser == 1 %}超级管理员 {% else %} 普通用户 {% endif %} {{ user.cn_name }} {{ user.phone }} {{ user.get_sex_display }} {% if user.is_active == 1 %} | {% elif user.is_active == 0 %} | {% else %} 未知 {% endif %} {% if user.last_login == None %}未登录{% else %} {{ user.last_login }} {% endif %} 编辑 删除

    显示 [{{ page_obj.paginator.count }}] 条数据中的 第 [{{ page_obj.start_index }}] 至 [{{ page_obj.end_index }}] 的数据

    {% if page_obj.paginator.num_pages > 1 %} {% include '_paginator.html' %} {% endif %}
    {% endblock %} {% block js %} {% endblock %}

    参数解读:

    • 添加用户按钮:通过页面表单方式实现用户添加;
    • users:为后端 UserListViewcontext_object_name传递过来的;
    • 编辑按钮:和添加用户类型;
    • 删除按钮:通过ajax的弹窗方式进行删除,没有用到页面;
  • 效果图


1.4 用户更新

  • 视图配置

    # mysite/users/views.py
    
    from .form import UserModelForm
    from django.views.generic import UpdateView
    from django.contrib.auth import get_user_model
    from django.contrib.messages.views import SuccessMessageMixin
    
    User = get_user_model()
    
    class UserEditView(SuccessMessageMixin, UpdateView):
        """"
        更新用户
        """
        template_name = 'users/form.html'
        model = User
        form_class = UserModelForm
        success_message = '%(username)s was update successfully'
    
        def get_success_url(self):
            # print(self.request.POST)
            if '_savedit' in self.request.POST:
                # print(self.object.pk)
                # 是一个ID
                return reverse('users:useredit', kwargs={'pk':self.object.pk})
            return reverse('users:userlist')
    
    
        def form_valid(self, form):
            new_password = form.cleaned_data['password']
            # print(self.object)
            # 是一个用户
            self.object.set_password(new_password)
            self.object.save()
            return super(UserEditView, self).form_valid(form)
    

    参数解读:跟CreateView类似。

  • 模板配置

    用户添加的模板一致,共用一个模板。

  • 效果图

1.5 用户删除

  • 视图配置

    from django.views.generic import DeleteView
    from django.contrib.auth import get_user_model
    
    User = get_user_model()
    
    class UserDelView(DeleteView):
        """
        删除用户
        """
        model = User
    
        def post(self, request, *args, **kwargs):
            # pk = self.kwargs
            # print(pk)
            try:
                self.get_object().delete()
                res = {"code": 0, "result": "删除用户成功"}
            except:
                log.error('delete user error:{}'.format(traceback.format_exc()))
                res = {"code": 1, "result": "删除用户失败"}
            return JsonResponse(res, safe=True)
    
  • 模板配置

    通过调用ajax删除用户,参考章节用户查看的模板文件。

  • 效果图

总结:终于码完这篇文章了,虽然看起来就4个项目:用户的增删改查,其实一点都不容易,五味杂陈啊。我还是把CBV里的CreateViewListViewUpadteViewDeleteView都一一对应起来了,其实方法还是有很多种的。

现在用户管理差不多就这样了,各位还可以持续去优化,做的更好,那么用户登陆认证怎么实现呢?待我去码下一篇文章...敬请期待!

如果喜欢的我的文章,欢迎关注我的公号:点滴技术,扫码关注,不定期分享

你可能感兴趣的:(Django之用户管理系统CBV-全新升级(5))