有趣的灵魂

往事浓淡 色如清 已轻,经年悲喜 净如镜 已静。
返回顶部
扩大
缩小

Django实战1-权限管理功能实现-10:用户管理

这节将会介绍用户管理功能的实现,包括用户信息浏览、添加、删除和修改等操作,从这一节开始很多功能实现都是和前面组织架构管理功能实现类似,所以通过这一节我们将完整实现用户管理功能。

1 用户列表展示

为了能够在列表中展示所有的用户信息,我们需要写两个视图,一个是用来提供模板页的基础视图,另外一个是用来访问用户数据列表的接口视图,然后通过使用ajax将数据组合填充到datatables中进行展示。

1.1 视图配置

打开sandboxMP/apps/system/views_user.py, 添加如下内容

import json

from django.views.generic.base import TemplateView
from django.shortcuts import HttpResponse
from django.contrib.auth import get_user_model

User = get_user_model()

class UserView(LoginRequiredMixin, TemplateView):
    template_name = 'system/users/user.html'


class UserListView(LoginRequiredMixin, View):
    def get(self, request):
        fields = ['id', 'name', 'gender', 'mobile', 'email', 'department__name', 'post', 'superior__name', 'is_active']
        ret = dict(data=list(User.objects.values(*fields)))
        return HttpResponse(json.dumps(ret), content_type='application/json')

知识点介绍:

1、UserView:继承了TemplateView基本类视图,通过template_name指定返回的模板页
2、UserListView:通过QuerySetvalues方法来获取指定字段列的数据内容,转换QuerySet类型最终序列化成json串,返回数据访问接口
3User = get_user_model():使用自定义用户模型的方法
4、department__name:departent是外键,默认存储在数据库里面的是department_id, 使用这种写法可以直接通过QuerySetvalues方法获取departmentname值,类似的还有superior__name

1.2 URL配置

打开 sandboxMP/apps/system/urls.py, 添加新的url:

from . import views_user

app_name = 'system'

urlpatterns = [
    ...原有内容省略...
    path('basic/user/', views_user.UserView.as_view(), name='basic-user'),
    path('basic/user/list/', views_user.UserListView.as_view(), name='basic-user-list'),
]

# 完成以上配置第一个url : http://127.0.0.1:8000/system/basic/user/是会报错的,
# 错误信息:TemplageDoesNotExist,因为我肯还没有配置模板;
# 第二个URL是可以访问的:http://127.0.0.1:8000/system/basic/user/list/
# 因为UserListView返回的是一个json数据接口

1.3 模板配置

复制sandboxMP/template/index.html 文件到sandboxMP/template/system/users/目录下,重命名为user.html, 并修改内容如下:

{% extends "base-left.html" %}
{% load staticfiles %}

{% block css %}
    
{% endblock %}

{% block content %}

    <!-- Main content -->
  <section class="content">

    当前访问页:用户管理, 这里是用户管理的基本页,用户管理所有模板页内容将会在这里添加
  </section>

    <!-- /.content -->

{% endblock %}


{% block javascripts %}

{% endblock %}

这时候就可以访问我们的用户管理页面了:http://127.0.0.1:8000/system/basic/user/
接下来继续修改我们的user.html模板页,使用datatables来展示我们的用户数列表

1、修改user.html文件,删除section标签中刚才添加的临时内容,然后在section标签中写入下面的内容:

<div id="devlist">
    <div class="box box-primary" id="liebiao">
        <div class="box-header">
            <div class="btn-group pull-left">
                <button type="button" id="btnRefresh" class="btn btn-default">
                    <i class="glyphicon glyphicon-repeat"></i>刷新
                </button>
            </div>
            <div class="btn-group pull-left">&nbsp</div>
            <div class="btn-group pull-left">
                <button type="button" id="btnCreate" class="btn btn-default">
                    <i class="glyphicon glyphicon-plus"></i>新增
                </button>
            </div>
            <div class="btn-group pull-left">&nbsp</div>
            <div class="btn-group pull-left">
                <button type="button" id="btnDelete" class="btn btn-default">
                    <i class="glyphicon glyphicon-trash"></i>删除
                </button>
            </div>
            <div class="btn-group pull-left">&nbsp</div>
            <div class="btn-group pull-left">
                <button type="button" id="btnEnable" class="btn btn-default">
                    <i class="glyphicon glyphicon-ok-circle"></i>启用
                </button>
                <button type="button" id="btnDisable" class="btn btn-default">
                    <i class="glyphicon glyphicon-ban-circle"></i>禁用
                </button>
            </div>
            <div class="btn-group pull-right">
                <form class="form-inline">
                    <div class="form-group">
                        <label>用户状态:</label>
                        <select id="select" name="select" class="form-control">
                            <option style='text-align:center' value=''>-----所有-----</option>
                            <option value="True">启用</option>
                            <option value="False">禁用</option>
                        </select>
                    </div>
                </form>
            </div>
        </div>
        <div class="box-body">
            <table id="dtbList" class="display" cellspacing="0" width="100%">
                <thead>
                <tr valign="middle">
                    <th><input type="checkbox" id="checkAll"></th>
                    <th>ID</th>
                    <th>姓名</th>
                    <th>性别</th>
                    <th>手机</th>
                    <th>邮箱</th>
                    <th>部门</th>
                    <th>职位</th>
                    <th>上级</th>
                    <th>状态</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
            <br> <br>
        </div>
    </div>
</div>

模板内容说明:

  • 定义了用户管理的一些操作按钮,包含 新建、删除、启用、停用等,按钮都定义了id,用来关联js方法
  • 定义了用户列表基本表格,表头和UserListView中的fields内容是一致的

页面访问效果(http://127.0.0.1:8000/system/basic/user/): 

2、接着修改user.html文件,使用datatables来展示用户数据:

引用样式文件,写到{% block css %}标签下:

<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}">
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">

引用js文件并进行表格初始化,写到{% block javascripts %}标签下:

<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'plugins/datatables/dataTables.const.js' %}"></script>
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>

<script type="text/javascript">
    var oDataTable = null;
    $(function () {
        oDataTable = initTable();

        function initTable() {
            var oTable = $('#dtbList').DataTable($.extend(true, {},
                DATATABLES_CONSTANT.DATA_TABLES.DEFAULT_OPTION,
                {
                    ajax: {
                        "url": "{% url 'system:basic-user-list' %}",
                    },
                    columns: [
                        DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
                        {
                            data: "id",
                            width: "5%",
                        },
                        {
                            data: "name",//parent
                            width: "10%",
                        },
                        {
                            data: "gender",
                            width: "10%",
                            render: function (data, type, row, meta) {
                                if (data == 'male') {
                                    return "男";
                                } else {
                                    return "女";
                                }
                            }
                        },
                        {
                            data: "mobile",
                        },
                        {
                            data: "email",
                        },
                        {
                            data: "department__name",
                        },

                        {
                            data: "post",
                        },
                        {
                            data: "superior__name",
                        },
                        {
                            data: "is_active",
                            render: function (data) {
                                if (data == true) {
                                    return "启用";
                                } else {
                                    return "禁用";
                                }
                            }
                        },
                        {
                            data: "id",
                            width: "12%",
                            bSortable: "false",
                            render: function (data, type, row, meta) {
                                var ret = "";
                                var ret = "<button title='详情-编辑' onclick='doUpdate("
                                    + data + ")'><i class='glyphicon glyphicon-pencil'></i></button>";
                                ret = ret + "<button name='btnChangepasswd' title='修改密码' onclick='doChangepasswd("
                                    + data + ")'><i class='glyphicon glyphicon-asterisk'></i></button>";
                                ret = ret + "<button name='btnConfig' title='删除' onclick='doDelete("
                                    + data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
                                return ret;
                            }
                        }],
                    "order": [
                        [2, 'desc']
                    ],
                }));
            return oTable;
        }
    });
</script>

Ctrl+F5刷新用户管理页面,就可以看到用户数据已经通过datatables在页面上展示了。

知识点介绍:

我们在初始化datatables配置的js中写到:
ajax: {
    "url": "{% url 'system:basic-user-list' %}",
},
1、通过ajax请求/system/base/user/userlist接口来获取数据;
2、{% url 'system:basic-user-list' %}是使用了DJANGO URL的反向解析功能,避免URL的硬编码,URL变更,不会影响到模板中的URL解析
3、在django后台也可以使用reverse()函数来进行URL的反响解析,实际上我们在用户登出的LogoutView视图已经使用到了reverse()函数
4columns:datatables的一个属性方法,用来将通过ajax获取到的json数据渲染到表格中去,其中data指定的字段需和后台传递过来的数据字段名称一致,并和html中定义的表头顺寻一致

2 添加用户

在添加用户时,我们需要对输入的数据进行有效性验证,包括:密码长度和有效性验证、关键字段的有效性验证、用户名重复性验证、手机号码有效性验证、手机号码重复性验证等等,同时还要对错误输入提供有效的错误提示信息,看起来要求很多,不过好在django表单功能提供了各种验证方法。

2.1 创建UserCreateForm

打开sandboxMP/apps/system/forms.py, 添加如下内容:

import re

from django.contrib.auth import get_user_model

User = get_user_model()


class UserCreateForm(forms.ModelForm):
    password = forms.CharField(
        required=True,
        min_length=6,
        max_length=20,
        error_messages={
            "required": "密码不能为空",
            "min_length": "密码长度最少6位数",
        }
    )

    confirm_password = forms.CharField(
        required=True,
        min_length=6,
        max_length=20,
        error_messages={
            "required": "确认密码不能为空",
            "min_length": "密码长度最少6位数",
        }
    )

    class Meta:
        model = User
        fields = [
            'name', 'gender', 'birthday', 'username', 'mobile', 'email',
            'department', 'post', 'superior', 'is_active', 'roles', 'password'
        ]

        error_messages = {
            "name": {"required": "姓名不能为空"},
            "username": {"required": "用户名不能为空"},
            "email": {"required": "邮箱不能为空"},
            "mobile": {
                "required": "手机号码不能为空",
                "max_length": "输入有效的手机号码",
                "min_length": "输入有效的手机号码"
            }
         }

    def clean(self):
        cleaned_data = super(UserCreateForm, self).clean()
        username = cleaned_data.get("username")
        mobile = cleaned_data.get("mobile", "")
        email = cleaned_data.get("email")
        password = cleaned_data.get("password")
        confirm_password = cleaned_data.get("confirm_password")

        if User.objects.filter(username=username).count():
            raise forms.ValidationError('用户名:{}已存在'.format(username))

        if password != confirm_password:
            raise forms.ValidationError("两次密码输入不一致")

        if User.objects.filter(mobile=mobile).count():
            raise forms.ValidationError('手机号码:{}已存在'.format(mobile))

        REGEX_MOBILE = "^1[3578]\d{9}$|^147\d{8}$|^176\d{8}$"
        if not re.match(REGEX_MOBILE, mobile):
            raise forms.ValidationError("手机号码非法")

        if User.objects.filter(email=email).count():
            raise forms.ValidationError('邮箱:{}已存在'.format(email))

知识点介绍:

1、error_messages:表单字段的关键参数,通过覆盖字段引发的异常中的默认信息,实现自定义错误提示信息。
2、clean()方法:重写clean()方法可以实现额外的验证功能。
3、ValidationError:当form验证的数据有问题都会引发ValidationError,并将相关的错误信息传递给
ValidationError,项目中通过重写clean()方法对输入的数据进行额外验证,不合规的数据输入将会触发ValidationError,返回错误信息。

2.2 用户添加视图

import re

from django.contrib.auth.hashers import make_password

from .forms import UserCreateForm
from .models import Structure, Role


class UserCreateView(LoginRequiredMixin, View):

    def get(self, request):
        users = User.objects.exclude(username='admin')
        structures = Structure.objects.values()
        roles = Role.objects.values()

        ret = {
            'users': users,
            'structures': structures,
            'roles': roles,
        }
        return render(request, 'system/users/user_create.html', ret)

    def post(self, request):
        user_create_form = UserCreateForm(request.POST)
        if user_create_form.is_valid():
            new_user = user_create_form.save(commit=False)
            new_user.password = make_password(user_create_form.cleaned_data['password'])
            new_user.save()
            user_create_form.save_m2m()
            ret = {'status': 'success'}
        else:
            pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
            errors = str(user_create_form.errors)
            user_create_form_errors = re.findall(pattern, errors)
            ret = {
                'status': 'fail',
                'user_create_form_errors': user_create_form_errors[0]
            }
        return HttpResponse(json.dumps(ret), content_type='application/json')

知识点介绍:

  • 通过get()方法返回添加用户的模板页,同时传递了ret上下文内容,用来作为添加用户时的选择字段。
  • exclude(**kwargs):QuerySet方法,排除给定的对象,返回不包含给定对象的QuerySet。
  • user_create_form.save(commit=False):在添加组织架构一节,已经使用到form.save()方法来存储数据,这里使用save(commit=False),指定commit=False,当通过表单获取模型数据后,在调用save()方法时不会将数据存储到数据库,而是返回一个当前对象,这样我们就可以添加表单以外的数据,然后在一再存储到数据库。
  • make_password:django自带加密模块,这里使用时为了将密码以密文形式存储到数据库。
  • save_m2m(): 用来存储多对多的关系,添加用户时绑定的角色组为多对多关系,实际上使用form.save()方法是可以直接存储多对多关系的,因为我们前面使用了save(commit=False)方法,所以这里要使用save_m2m()方法。
  • user_create_form.errors:获取表单验证的错误信息,默认获得一个错误信息的字典格式,也可以使用form.errors.as_json()来返回JSON序列化后的错误信息。
  • user_create_form_errors[0]:这里对错误信息进行了处理,只返回文字信息,并且每次只返回一个错误信息。

2.3 URL配置

打开sandboxMP/apps/system/urls.py,添加新增用户的URL:

urlpatterns = [
    '''原有内容省略'''
    path('basic/user/create/', views_user.UserCreateView.as_view(), name='basic-user-create'),
]

2.4 添加用户的模板配置

新建添加模板:sandboxMP/templates/system/users/user_create.html,内容如下:

{% extends 'base-layer.html' %}
{% load staticfiles %}

{% block css %}
    <link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap-datetimepicker.min.css' %}">
    <link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
{% endblock %}

{% block main %}
    <div class="box box-danger">
        <form class="form-horizontal" id="addForm" method="post">
            {% csrf_token %}
            <input type="hidden" name='id' value="{{ user.id }}"/>
            <input type="hidden" name='user' value="save"/>
            <div class="box-body">
                <fieldset>
                    <legend>
                        <h4>基本信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">姓名</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="name" type="text" value=""/>
                        </div>
                        <label class="col-sm-2 control-label">性别</label>
                        <div class="col-sm-3">
                            <select class="form-control" name="gender">
                                <option value="male"></option>
                                <option value="female"></option>
                            </select>
                        </div>

                    </div>

                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">生日</label>
                        <div class="col-sm-3">
                            <input type="text" class="form-control pull-right form_datetime" name="birthday"/>
                        </div>
                        <label class="col-sm-2 control-label">用户名</label>
                        <div class="col-sm-3">
                            <input type="text" class="form-control" name="username"/>
                        </div>
                    </div>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">状态</label>
                        <div class="col-sm-6">
                            <label class="control-label">
                                <input type="radio" class="minimal" name="is_active" value="True" checked>启用
                            </label>
                            <label class="control-label">
                                <input type="radio" class="minimal" name="is_active" value="False">禁用
                            </label>
                        </div>
                    </div>
                    <legend>
                        <h4>密码信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">密码</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="password" type="password" value=""/>
                        </div>
                        <label class="col-sm-2 control-label">确认密码</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="confirm_password" type="password" value=""/>
                        </div>
                    </div>
                    <legend>
                        <h4>联系信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">手机</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="mobile" type="text"/>
                        </div>
                        <label class="col-sm-2 control-label">邮箱</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="email" type="text"/>
                        </div>
                    </div>
                    <legend>
                        <h4>职员信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">入职日期</label>
                        <div class="col-sm-3">
                            <input type="text" class="form-control pull-right form_datetime" name="joined_date"/>
                        </div>
                        <label class="col-sm-2 control-label">部门</label>
                        <div class="col-sm-3">
                            <select class="form-control select2" style="width:100%;" name="department">
                                <option value="">--部门--</option>
                                {% for structure in structures %}
                                    <option value="{{ structure.id }}">{{ structure.name }}</option>
                                {% endfor %}
                            </select>
                        </div>

                    </div>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">岗位</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="post" type="text"/>
                        </div>
                        <label class="col-sm-2 control-label">上级</label>
                        <div class="col-sm-3">
                            <select class="form-control select2" style="width:100%;" name="superior">
                                <option value="">--上级--</option>
                                {% for user in users %}<option value="{{ user.id }}">{{ user.name }}</option>
                                {% endfor %}</select>
                        </div>

                    </div>

                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">所属角色组</label>
                        <div class="col-sm-6">
                            {% for role in roles %}<label class="control-label">
                                    <input type="checkbox" class="minimal" name="roles" value="{{ role.id }}"
                                           {% if role in user_roles %}checked{% endif %}>
                                    {{ role.name }}</label>
                            {% endfor %}</div>
                    </div>
                </fieldset>

            </div>
            <div class="box-footer ">
                <div class="row span7 text-center ">
                    <button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
                    <button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
                </div>
            </div>

        </form>
    </div>

{% endblock %}{% block javascripts %}<script src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
    <script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
    <script type="text/javascript">

        $("#btnSave").click(function () {
            var data = $("#addForm").serialize();
            $.ajax({
                type: $("#addForm").attr('method'),
                url: "{% url 'system:basic-user-create' %}",
                data: data,
                cache: false,
                success: function (msg) {
                    if (msg.status == 'success') {
                        layer.alert('用户添加成功!', {icon: 1}, function (index) {
                            parent.layer.closeAll(); //关闭所有弹窗
                        });
                    } else if (msg.status == 'fail') {
                        layer.alert(msg.user_create_form_errors, {icon: 5});
                        //$('errorMessage').html(msg.message)
                    }
                    return;
                }
            });
        });


        /*点取消刷新新页面*/
        $("#btnCancel").click(function () {
            window.location.reload();

        })

        /*input 时间输入选择*/
        $(".form_datetime").datetimepicker({
            language: 'zh',
            minView: 'month', //选择范围只到日期,不选择时分
            //weekStart: 1,
            //todayBtn:  1,
            autoclose: 1,
            todayHighlight: 1,
            //startView: 2,
            forceParse: 0,
            showMeridian: 1,
            format: 'yyyy-mm-dd'
        }).on('changeDate', function (ev) {
            $(this).datetimepicker('hide');
        });

        $(function () {
            //Initialize Select2 Elements
            $(".select2").select2();
        });

    </script>

{% endblock %}

知识点介绍:

  • 该模板用户添加弹窗,继承了base-layer.html模板,定义了条件用户的form表单
  • $("#btnSave").click(function ():定义了保存按钮的点击事件,通过判断后端返回的status来提示响应信息。

2.5 为添加按钮绑定事件

我们在用户管理页面已经定义了添加用户的按钮,打开sandboxMP/templates/system/users/user.html,在 {% block javascripts %}标签下添加如下内容(放到datatables初始化配置的后面):

<script type="text/javascript">
    $("#btnCreate").click(function () {
        var div = layer.open({
            type: 2,
            title: '新增',
            shadeClose: false,
            maxmin: true,
            area: ['800px', '720px'],
            content: '/system/basic/user/create',
            end: function () {
                //关闭时做的事情
                oDataTable.ajax.reload();
            }
        });
        layer.full(div)
    });
</script>

至此,访问用户管理页面:http://127.0.0.1:8000/system/basic/user/, 点击新增按钮就可以添加新的用户了,大家也可以在添加用户的时候打上断点Debug一下,了解form验证和错误信息的提示效果。 

3 用户详情

用户详情页用于查看用户详情信息和修改用户信息。

3.1 用户详情视图

打开sandboxMP/apps/system/views_user.py,添加下面内容:

from django.shortcuts import get_object_or_404
from django.db.models import Q

class UserDetailView(LoginRequiredMixin, View):

    def get(self, request):
        user = get_object_or_404(User, pk=int(request.GET['id']))
        users = User.objects.exclude(Q(id=int(request.GET['id'])) | Q(username='admin'))
        structures = Structure.objects.values()
        roles = Role.objects.values()
        user_roles = user.roles.values()
        ret = {
            'user': user,
            'structures': structures,
            'users': users,
            'roles': roles,
            'user_roles': user_roles
        }
        return render(request, 'system/users/user_detail.html', ret)

知识点介绍:

  • 用户详情视图同时也用于用户数据的更新视图,上下文数据除了包括选中用户的详情信息外,同时还传递了,修改用户数据时的一些选择项,例如角色组,组织架构等.
  • UserDetailView视图中只定义了get()方法,并未定义用来接收前端传递的修改数据信息和存储修改数据的post()方法,这是因为用户数据修改分为两种类型:一种是管理员通过用户管理来修改指定的用户信息,另外一种是已登录用户通过用户中心修改个人用户信息,所以这里把post()方法拿出去单独新建了一个更新的视图.
  • users = User.objects.exclude(Q(id=int(request.GET['id'])) | Q(username='admin')):修改用户数据时,可以通过select选择用户的上级,这里在做查询的时候我们使用exclude()方法排除了当前选中的用户和系统的默认用户,其中Q()对象就是用来构建负载的数据库查询他,它支持使用 | (OR) 和 & (AND).

3.2 用户详情URL配置

打开sandboxMP/apps/system/urls.py,添加用户详情访问URL:

urlpatterns = [
    '''原有内容省略'''
    path('basic/user/detail/', views_user.UserDetailView.as_view(), name='basic-user-detail'),
]

3.3 用户详情页模板配置

修建用户详情页模板:sandboxMP/templates/system/users/user_detail.html,内容如下:

{% extends 'base-layer.html' %}
{% load staticfiles %}

{% block css %}
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap-datetimepicker.min.css' %}">
    <link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
{% endblock %}

{% block main %}
    <div class="box box-danger">
        <form class="form-horizontal" id="addForm" method="post">
            {% csrf_token %}
            <!-- 请查看下面知识点介绍中注释1:-->
            <input type="hidden" name='id' value="{{ user.id }}"/>
            <input type="hidden" name='user' value="save"/>
            <div class="box-body">
                <fieldset>
                    <legend>
                        <h4>基本信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">姓名</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="name" type="text" value="{{ user.name }}"/>
                        </div>
                        <label class="col-sm-2 control-label">性别</label>
                        <div class="col-sm-3">
                            <select class="form-control" name="gender">
                                <option value={{ user.gender }}> {{ user.get_gender_display }} </option>
                                <option value="male"></option>
                                <option value="female"></option>
                            </select>
                        </div>

                    </div>

                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">生日</label>
                        <div class="col-sm-3">
                            <input type="text" class="form-control pull-right form_datetime" name="birthday"
                                   value="{{ user.birthday|date:"Y-m-d" }}"/>
                        </div>
                        <label class="col-sm-2 control-label">用户名</label>
                        <div class="col-sm-3">
                            <input type="text" class="form-control" name="username" readonly="readonly"
                                   value="{{ user.username }}"/>
                        </div>
                    </div>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">状态</label>
                        <div class="col-sm-6">
                            <label class="control-label">
                                <input type="radio" class="minimal" name="is_active" value="True"
                                       {% ifequal user.is_active True %}checked{% endifequal %}>启用
                            </label>
                            <label class="control-label">
                                <input type="radio" class="minimal" name="is_active" value="False"
                                       {% ifequal user.is_active False %}checked{% endifequal %}>禁用
                            </label>
                        </div>
                    </div>
                    <legend>
                        <h4 clase="">联系信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">手机</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="mobile" readonly="readonly" type="text"
                                   value="{{ user.mobile }}"/>
                        </div>
                        <label class="col-sm-2 control-label">邮箱</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="email" type="text" value="{{ user.email }}"/>
                        </div>
                    </div>
                    <legend>
                        <h4>职员信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">入职日期</label>
                        <div class="col-sm-3">
                        <!-- 请查看下面知识点介绍中注释2:-->
                            <input type="text" class="form-control pull-right form_datetime" name="joined_date"
                                   value="{{ user.joined_date|date:"Y-m-d" }}"/>
                        </div>
                        <label class="col-sm-2 control-label">部门</label>
                        <div class="col-sm-3">
                            <select class="form-control select2" style="width:100%;" name="department">
                                <option value="{{ user.department.id }}">{{ user.department.name|default:"--部门--" }}</option>
                                {% for structure in structures %}
                                    <option value="{{ structure.id }}">{{ structure.name }}</option>
                                {% endfor %}
                            </select>
                        </div>

                    </div>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">岗位</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="post" type="text"
                                   value="{{ user.post|default_if_none:"" }}"/>
                        </div>
                        <label class="col-sm-2 control-label">上级</label>
                        <div class="col-sm-3">
                            <select class="form-control select2" style="width:100%;" name="superior">
                                <option value="{{ user.superior.id }}">{{ user.superior.name|default:"--上级--" }}</option>
                                {% for user in users %}<option value="{{ user.id }}">{{ user.name }}</option>
                                {% endfor %}</select>
                        </div>

                    </div>

                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">所属角色组</label>
                        <div class="col-sm-6">
                            {% for role in roles %}<label class="control-label">
                                    <input type="checkbox" class="minimal" name="roles" value="{{ role.id }}"
                                           {% if role in user_roles %}checked{% endif %}>
                                    {{ role.name }}</label>
                            {% endfor %}</div>
                    </div>
                </fieldset>

            </div>
            <div class="box-footer ">
                <div class="row span7 text-center ">
                    <button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
                    <button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
                </div>
            </div>

        </form>
    </div>

{% endblock %}{% block javascripts %}<script src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
    <script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
   <script type="text/javascript">/*点取消刷新新页面*/
        $("#btnCancel").click(function () {
            window.location.reload();

        })

        /*input 时间输入选择*/
        $(".form_datetime").datetimepicker({
            language: 'zh',
            minView: 'month',
            //weekStart: 1,
            //todayBtn:  1,
            autoclose: 1,
            todayHighlight: 1,
            //startView: 2,
            forceParse: 0,
            showMeridian: 1,
            format: 'yyyy-mm-dd'
        }).on('changeDate', function (ev) {
            $(this).datetimepicker('hide');
        });

        $(function () {
            //Initialize Select2 Elements
            $(".select2").select2();
        });
        
    </script>
{% endblock %}

知识点介绍(对应代码中注释部分):

  • 注释1:我们在所有修改数据信息的视图都会写一条隐藏的input用来向后台传递修改数据条目的id, 然后后台通过POST方法获取到id,在通过QuerySet查询到该id对应的实例,保存修改信息。
  • 注释2:这里使用了django模板内置的过滤器date根据给定的格式对一个date变量进行格式化,上面代码中我们还使用了default_if_none过滤器,当value为None,则使用给定的默认值,django还提供了很多好用的过滤器,有兴趣可以查看下官方文档。

3.4 为用户详情-修改按钮绑定点击事件

打开sandboxMP/templates/system/users/user.html,在{% block javascripts %}标签中的$("#btnCreate")方法后面添加如下内容:


// 跳转到用户详情页面
function doUpdate(id) {
    var div = layer.open({
        type: 2,
        title: '编辑',
        shadeClose: false,
        maxmin: true,
        area: ['800px', '650px'],
        content: ["{% url 'system:basic-user-detail' %}" + '?id=' + id, 'no'],
        end: function () {
            oDataTable.ajax.reload();
        }
    });
    layer.full(div)
}

在datatables初始化配置的时候,已经为表格中每一条数据生成了【详情-修改】按钮,同时绑定了doUpdate()函数,同时将选中数据id传递给改函数,当我们点击该按钮时候,系统会把当前选中用户数据id传递到后台,获取用户详细数据。
运行系统,访问用户管理页面:http://127.0.0.1:8000/system/basic/user/

点击数据条目后面的详情-编辑按钮就可以访问用户详情页面:

4 用户更新

前面已经实现用户详情信息的访问,并且在详情页可以修改用户信息,接下来还需要写一个更新视图,用来接收用户修改信息,保存到数据库

4.1 创建UserUpdateForm

打开sandboxMP/apps/system/forms.py,添加如下内容:

class UserUpdateForm(forms.ModelForm):
    class Meta:
        model = User
        fields = [
            'name', 'gender', 'birthday', 'username', 'mobile', 'email',
            'department', 'post', 'superior', 'is_active', 'roles'
        ]

我们定义了一个form类用来验证用户更新输入的数据,比起添加用户的验证要简单的多,因为我们将会在前端限制关键字段的修改,包括:用户名、手机号码和邮箱等

4.2 用户更新视图

打开sandboxMP/apps/system/views_user.py,新增用户更新视图

from .forms import UserUpdateForm

class UserUpdateView(LoginRequiredMixin, View):

    def post(self, request):
        if 'id' in request.POST and request.POST['id']:
            user = get_object_or_404(User, pk=int(request.POST['id']))
        else:
            user = get_object_or_404(User, pk=int(request.user.id))
        user_update_form = UserUpdateForm(request.POST, instance=user)
        if user_update_form.is_valid():
            user_update_form.save()
            ret = {"status": "success"}
        else:
            ret = {"status": "fail", "message": user_update_form.errors}
        return HttpResponse(json.dumps(ret), content_type="application/json")

实现思路:
1、从request.POST中获取前端传递过来的需要修改的用户id
2、从用户模型中通过id查找改用户实例
3、将该用户实例出传递给UserUpdateForm
4、通过form.is_valid()方法验证输入数据是否合法
5、使用form.save()方法保存数据
6、返回最终执行结果

注意:如果request.POST中没有传递用户id,则默认用户是修改当前登陆的用户信息,所以会查找当前登陆用户的实例,这样做是为了让用户更新视图同时可以用于用户中心,修改个人信息。

4.3 添加用户更新URL

打开sandboxMP/apps/system/urls.py,添加用户更新URL

urlpatterns = [
    '''原有内容省略'''
    path('basic/user/update/', views_user.UserUpdateView.as_view(), name='basic-user-update'),

]

4.3 为用户详情页的保存按钮绑定事件

用户信息修改和用户详情页使用的是同一个页面,在用户详情页已经定义好了保存按钮,接下来只需要当定提交事件即可,修改 sandboxMP/templates/system/users/user_detail.html,在{% block javascripts %}标签下添加如下内容:

$(function () {
    //Initialize Select2 Elements
    $(".select2").select2();
});

//分界线,下面是新添加的内容
$("#btnSave").click(function () {
    var data = $("#addForm").serialize();
    $.ajax({
        type: $("#addForm").attr('method'),
        url: "{% url 'system:basic-user-update' %}",
        data: data,
        cache: false,
        success: function (msg) {
            if (msg.status == 'success') {
                layer.alert('数据保存成功!', {icon: 1}, function (index) {
                    parent.layer.closeAll(); //关闭所有弹窗
                });
            } else if (msg.status == 'fail') {
                layer.alert('数据保存失败', {icon: 5});
                //$('errorMessage').html(msg.message)
            }
            return;
        }
    });
});

到这里运行系统,访问用户管理页:http://127.0.0.1:8000/system/basic/user/, 选择表格中的 【详情-修改】按钮,在打开的弹窗中就可以修改我们的用户信息,然后通过保存按钮来保存数据。
注意:系统一开始创建的admin用户是没法修改的, 因为关键参数手机字段在前端是禁止修改的,admin用户添加的时候没有写入手机号码,所以提交的时候这个字段是空的,数据无法保存,可以通过数据库先添加下手机号码。

5 修改用户密码

用户管理页表格最后一列中间一个按钮是用来修改密码的按钮,管理员可以通过这个按钮来修改对应用户的密码。

5.1 创建PasswordChangeForm

在sandboxMP/apps/system/forms.py中创建PasswordChangeForm用来验证密码数据:

class PasswordChangeForm(forms.Form):

    password = forms.CharField(
        required=True,
        min_length=6,
        max_length=20,
        error_messages={
            "required": u"密码不能为空"
        })

    confirm_password = forms.CharField(
        required=True,
        min_length=6,
        max_length=20,
        error_messages={
            "required": u"确认密码不能为空"
        })

    def clean(self):
        cleaned_data = super(PasswordChangeForm, self).clean()
        password = cleaned_data.get("password")
        confirm_password = cleaned_data.get("confirm_password")
        if password != confirm_password:
            raise forms.ValidationError("两次密码输入不一致")

实现思路:
1、使用django表单功能对用户两次输入的密码进行验证,包括空值验证和长度验证
2、通过重写clean()方法类定义额外的验证功能,判断两次输入密码如果不一样则触发ValidationError

5.2 密码修改视图

from .forms import PasswordChangeForm


class PasswordChangeView(LoginRequiredMixin, View):

    def get(self, request):
        ret = dict()
        if 'id' in request.GET and request.GET['id']:
            user = get_object_or_404(User, pk=int(request.GET.get('id')))
            ret['user'] = user
        return render(request, 'system/users/passwd_change.html', ret)

    def post(self, request):
        if 'id' in request.POST and request.POST['id']:
            user = get_object_or_404(User, pk=int(request.POST['id']))
            form = PasswordChangeForm(request.POST)
            if form.is_valid():
                new_password = request.POST['password']
                user.set_password(new_password)
                user.save()
                ret = {'status': 'success'}
            else:
                pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
                errors = str(form.errors)
                password_change_form_errors = re.findall(pattern, errors)
                ret = {
                    'status': 'fail',
                    'password_change_form_errors': password_change_form_errors[0]
                }
        return HttpResponse(json.dumps(ret), content_type='application/json')

实现思路:
1、通过get()方法返回用户修改的模板页
2、通过post()方法来验证保存新的密码信息
3、通过request.POST获取前端传递过来的用户id,通过id查找用户模型中的实例
4、通过form.is_valid()方法验证密码有效性
5、调用set_password()方法修改用户密码
6、调用save()方法保存密码信息到数据库
7、返回执行结果

5.3 修改密码URL配置

在sandboxMP/apps/system/urls.py文件中添加修改密码的url:

urlpatterns = [
    '''原有内容省略'''
    path('basic/user/password_change/', views_user.PasswordChangeView.as_view(), name='basic-user-password_change'),
]

5.4 模板配置

1、新建sandboxMP/templates/system/users/passwd_change.html, 内容如下:

{% extends 'base-layer.html' %}
{% load staticfiles %}

{% block css %}
{% endblock %}

{% block main %}
    <div class="box box-danger">
        <form class="form-horizontal" id="addForm" method="post">
            {% csrf_token %}
            <input type="hidden" name='id' value="{{ user.id }}"/>
            <input type="hidden" name='user' value="save"/>
            <div class="box-body">
                <fieldset>
                    <legend>
                        <h4>基本信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">姓名</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="name" type="text" readonly="readonly"
                                   value="{{ user.name }}"/>
                        </div>
                        <label class="col-sm-2 control-label">用户名</label>
                        <div class="col-sm-3">
                            <input type="text" class="form-control" name="username" readonly="readonly"
                                   value="{{ user.username }}"/>
                        </div>
                    </div>

                        <h4>密码信息</h4>
                    </legend>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">密码</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="password" type="password" value=""/>
                        </div>
                        <label class="col-sm-2 control-label">确认密码</label>
                        <div class="col-sm-3">
                            <input class="form-control" name="confirm_password" type="password" value=""/>
                        </div>
                    </div>

                </fieldset>

            </div>
            <div class="box-footer ">
                <div class="row span7 text-center ">
                    <button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
                    <button type="button" id="btnSave" class="btn btn-info margin-right ">确定</button>
                </div>
            </div>

        </form>
    </div>

{% endblock %}

{% block javascripts %}
    <script src="{% static 'plugins/combo-select/jquery.combo.select.js' %}"></script>
    <script src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
    <script type="text/javascript">

        $("#btnSave").click(function () {
            var data = $("#addForm").serialize();
            $.ajax({
                type: $("#addForm").attr('method'),
                url: "{% url 'system:basic-user-password_change' %}",
                data: data,
                cache: false,
                success: function (msg) {
                    if (msg.status == 'success') {
                        layer.alert('密码修改成功!', {icon: 1}, function (index) {
                            parent.layer.closeAll();
                        });
                    } else if (msg.status == 'fail') {
                        layer.alert(msg.password_change_form_errors, {icon: 5});
                        //$('errorMessage').html(msg.message)
                    }
                    return;
                }
            });
        });


        /*点取消刷新页面*/
        $("#btnCancel").click(function () {
            window.location.reload();

        })


    </script>

{% endblock %}

注意:密码和确认密码的input标签中name字段值是和form里面定义的一样。

2、修改用户管理页面模板sandboxMP/templates/system/users/user.html,在{% block javascripts %}标签中添加密码按钮绑定的函数:

// 新增内容放到doUpdate()函数后面
function doChangepasswd(id) {
    layer.open({
        type: 2,
        title: '修改密码',
        shadeClose: false,
        maxmin: true,
        area: ['850px', '350px'],
        content: ["{% url 'system:basic-user-password_change' %}" + '?id=' + id, 'no'],
        end: function () {
            oDataTable.ajax.reload();
        }
    });
}

在项目中我们弹窗组建使用的是layer,一个jquery弹窗组建,有关layer更多使用方法可以参考官方网站:https://layer.layui.com/

6、用户启用、禁用和删除

用户的启用、禁用和删除(支持批量操作),这个三部分功能的实现是一样的,所以这里把它们放到一起。

6.1 视图实现

打开sandboxMP/apps/system/views_user.py, 添加如下内容

class UserDeleteView(LoginRequiredMixin, View):
    """
    删除数据:支持删除单条记录和批量删除
    """

    def post(self, request):
        ret = dict(result=False)
        if 'id' in request.POST and request.POST['id']:
            id_list = map(int, request.POST['id'].split(','))
            User.objects.filter(id__in=id_list).delete()
            ret['result'] = True
        return HttpResponse(json.dumps(ret), content_type='application/json')


class UserEnableView(LoginRequiredMixin, View):
    """
    启用用户:单个或批量启用
    """

    def post(self, request):
        if 'id' in request.POST and request.POST['id']:
            id_nums = request.POST.get('id')
            queryset = User.objects.extra(where=["id IN(" + id_nums + ")"])
            queryset.filter(is_active=False).update(is_active=True)
            ret = {'result': 'True'}
        return HttpResponse(json.dumps(ret), content_type='application/json')


class UserDisableView(LoginRequiredMixin, View):
    """
    禁用用户:单个或批量禁用
    """

    def post(self, request):
        if 'id' in request.POST and request.POST['id']:
            id_nums = request.POST.get('id')
            queryset = User.objects.extra(where=["id IN(" + id_nums + ")"])
            queryset.filter(is_active=True).update(is_active=False)
            ret = {'result': 'True'}
        return HttpResponse(json.dumps(ret), content_type='application/json')

这三个视图实现的逻辑是一样的,首先通过request.POST获取前端提交过来的一组用户id,然后进行批量查找后进行删除或更新用户状态。
为了更多的让大家了解django QuerySet方法,上面三个视图中使用了两种方法进行批量查找: 1、User.objects.filter(id__in=id_list):使用filter方法查找数据时,在查找字段后加上双下划线和in,后面可以跟上列表,在给定的列表中进行查找,效果等同于SQL:SELECT...where in id_list; 2、extra(): 可以用来实现django查询语法难以表达的复杂的WHERE子句

6.2 URL配置

打开sandboxMP/apps/system/urls.py,添加新的URL:

urlpatterns = [
    '''原有内容省略'''
    path('basic/user/delete/', views_user.UserDeleteView.as_view(), name='basic-user-delete'),
    path('basic/user/enable/', views_user.UserEnableView.as_view(), name='basic-user-enable'),
    path('basic/user/disable/', views_user.UserDisableView.as_view(), name='basic-user-disable'),
]

6.3 模板配置

在用户管理的模板页中,已经添加了删除、启用、停用按钮,现在只需要给按钮绑定事件,将请求传递给对应的接口即可。
打开sandboxMP/templates/system/users/user.html,在{% block javascripts %}标签中添加如下代码:

// 以下代码添加到 doChangepasswd()函数后面

//checkbox全选
$("#checkAll").on("click", function () {
    if ($(this).prop("checked") === true) {
        $("input[name='checkList']").prop("checked", $(this).prop("checked"));
        $('#example tbody tr').addClass('selected');
    } else {
        $("input[name='checkList']").prop("checked", false);
        $('#example tbody tr').removeClass('selected');
    }
});

//批量删除
$("#btnDelete").click(function () {
    if ($("input[name='checkList']:checked").length == 0) {
        layer.msg("请选择要删除的记录");
        return;
    }

    var arrId = new Array();
    $("input[name='checkList']:checked").each(function () {
        //alert($(this).val());
        arrId.push($(this).val());
    });

    sId = arrId.join(',');

    layer.alert('确定删除吗?', {
        title: '提示'
        , icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
        , time: 0 //不自动关闭
        , btn: ['YES', 'NO']
        , yes: function (index) {
            layer.close(index);
            $.ajax({
                type: "POST",
                url: "{% url 'system:basic-user-delete' %}",
                data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
                cache: false,
                success: function (msg) {
                    if (msg.result) {
                        layer.alert("操作成功");
                        oDataTable.ajax.reload();
                    } else {
                        //alert(msg.message);
                        layer.alert("操作失败");
                    }
                    return;
                }
            });
        }
    });
});

//批量启用
$("#btnEnable").click(function () {
    if ($("input[name='checkList']:checked").length == 0) {
        layer.msg("请选择要启用的用户");
        return;
    }

    var arrId = new Array();
    $("input[name='checkList']:checked").each(function () {
        //alert($(this).val());
        arrId.push($(this).val());
    });

    sId = arrId.join(',');

    layer.alert('确定启用吗?', {
        title: '提示'
        , icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
        , time: 0 //不自动关闭
        , btn: ['YES', 'NO']
        , yes: function (index) {
            layer.close(index);
            $.ajax({
                type: "POST",
                url: "{% url 'system:basic-user-enable' %}",
                data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
                cache: false,
                success: function (msg) {
                    if (msg.result) {
                        layer.alert("启用用户成功", {icon: 1});
                        oDataTable.ajax.reload();
                    } else {
                        //alert(msg.message);
                        layer.alert("启用用户失败", {icon: 5});
                    }
                    return;
                }
            });
        }
    });
});

//批量禁用
$("#btnDisable").click(function () {
    if ($("input[name='checkList']:checked").length == 0) {
        layer.msg("请选择要禁用的用户");
        return;
    }

    var arrId = new Array();
    $("input[name='checkList']:checked").each(function () {
        //alert($(this).val());
        arrId.push($(this).val());
    });

    sId = arrId.join(',');

    layer.alert('确定禁用吗?', {
        title: '提示'
        , icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
        , time: 0 //不自动关闭
        , btn: ['YES', 'NO']
        , yes: function (index) {
            layer.close(index);
            $.ajax({
                type: "POST",
                url: "{% url 'system:basic-user-disable' %}",
                data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
                cache: false,
                success: function (msg) {
                    if (msg.result) {
                        layer.alert("禁用用户成功", {icon: 1});
                        oDataTable.ajax.reload();
                    } else {
                        //alert(msg.message);
                        layer.alert("禁用用户失败", {icon: 5});
                    }
                    return;
                }
            });
        }
    });
});

//删除单个用户
function doDelete(id) {
    layer.alert('确定删除吗?', {
        title: '提示'
        , icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
        , time: 0 //不自动关闭
        , btn: ['YES', 'NO']
        , yes: function (index) {
            layer.close(index);
            $.ajax({
                type: "POST",
                url: "{% url 'system:basic-user-delete' %}",
                data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'},  //防止post数据时报 csrf_token 403
                cache: false,
                success: function (msg) {
                    if (msg.result) {
                        layer.alert('删除成功', {icon: 1});
                        oDataTable.ajax.reload();
                    } else {
                        //alert(msg.message);
                        layer.alert('删除失败', {icon: 5});
                    }
                    return;
                }
            });
        }
    });

}

项目中大部分操作都是通过jquery-ajax和后端进行交互的,这里只需要掌握项目中的几种常用写法,在使用的时候会套用即可,当然如果你对jquery感兴趣,可以深入学习下。
运行项目,访问用户管理页就可以对用户进行批量删除、启用、停用操作了,你也可以通过表格中最后一列删除按钮来删除单个用户。

7 用户状态过滤

在用户管理也提供了一个用户状态过滤功能,可以快速通过状态过滤用户信息

7.1 修改UserListView视图

打开sandboxMP/apps/system/views.user.py,用户信息都是通过UserListView视图接口获取的,视图内容如下:

class UserListView(LoginRequiredMixin, View):
    def get(self, request):
        fields = ['id', 'name', 'gender', 'mobile', 'email', 'department__name', 'post', 'superior__name', 'is_active']
        ret = dict(data=list(User.objects.values(*fields)))
        return HttpResponse(json.dumps(ret), content_type='application/json')

UserListView 通过QuserSet查询返回了用户模型中所有实例信息,想要查询状态为启用或者禁用的用户信息,可以通过filter方法来实现,下面是改写后的代码:

class UserListView(LoginRequiredMixin, View):
    def get(self, request):
        fields = ['id', 'name', 'gender', 'mobile', 'email', 'department__name', 'post', 'superior__name', 'is_active']
        filters = dict()
        if 'select' in request.GET and request.GET['select']:
            filters['is_active'] = request.GET['select']
        ret = dict(data=list(User.objects.filter(**filters).values(*fields)))
        return HttpResponse(json.dumps(ret), content_type='application/json')

判断request.POST中是否包含'select'数据,如果包含则获取'select'值赋值给'is_active'(数据库中用户状态字段),通过filter方法查询符合的用户信息。

7.2 模板配置

1、先来看下sandboxMP/templates/system/users/user.html中用户状态过滤选择框的代码内容(user.html第42行开始):

<div class="btn-group pull-right">
    <form class="form-inline">
        <div class="form-group">
            <label>用户状态:</label>
            <select id="select" name="select" class="form-control">
                <option style='text-align:center' value=''>-----所有-----</option>
                <option value="True">启用</option>
                <option value="False">禁用</option>
            </select>
        </div>
    </form>
</div>

定义了一个form表单,表单提供过了一个select选择框,id和name为select,其中name名称也就是我们在后台通过request.GET['select']捕获该字段值时使用的内容,option标签中value值是实际传递到后台的数据。

2、打开sandboxMP/templates/system/users/user.html,在{% block javascripts %}标签中添中 datatables初始化配置的 ajax:代码段中添加下面内容:

 $(function () {
    oDataTable = initTable();

    function initTable() {
        var oTable = $('#dtbList').DataTable($.extend(true, {},
            DATATABLES_CONSTANT.DATA_TABLES.DEFAULT_OPTION,
            {
                ajax: {
                    "url": "{% url 'system:basic-user-list' %}",
                    // 下面三行是新增加的内容,
                    "data": function (d) {
                        d.select = $("#select").val();
                    }
                },

上面的ajax中 url为请求的地址,data为传递的参数,这个参数是通过$("#select").val()来获取用户状态过滤框中的内容,这个时候选择用户状态,表格中的数据是不会变化的,我们还需要将请求发送给后台,重新获取用户列表。

3、监控select选择框的变化 将下面代码放到user.html文件{% block javascripts %}标签中doDelete()函数后面

$("#select").change(function () {
    //alert($("#select").val())
    oDataTable.ajax.reload();
});

这样我们只要在用户状态框中选中用户状态,通过$("#select").change()方法监控到select状态变化了刷新datatables,这样datatables就通过ajax重新去用列表接口请求数据,同时传递select值,后端视图接收到请求,获取request.GET['select']值,通过filter查询返回数据结果。到这里完整的用户操作就全部实现了,通过上面方法你也可以尝试下做一些组合查询功能的实现。

posted on 2019-06-18 10:25  james的运维之路  阅读(672)  评论(0编辑  收藏  举报

导航