Django之用户管理系统CBV-全新升级(5)
时间过的真快,又接近4个月没更新文章了,不是我闲着,家里事情是真多,时间都给了溜娃还是溜娃,剩余点时间就学习Django
的知识,为了打磨好这一篇文章,可费了九牛二虎之力,完成该篇文章。
为了各位读者有较好的UI
视觉、有动力去学习和摸索,前端可投入不少时间。毕竟作为一名网工
,去搞前端,那还真不是一件容易的事情,你想,Django
这个后端知识体系已经够学一阵一阵子的了。
前端有啥学习?HTML、javascrip、jQuery、ajAX、Vue...
后端有啥学习?Django就够了...
前方高能,请看如下效果图...
文章图片
1.0 效果展示
说明:提前贴出这些图,希望各位看了有动力去学习。虽然django有自带一套用户系统,但是人的审美总是要有的哈,又可以提升下自己的代码水平.
- 用户列表展示
- 新增用户
文章图片
- 更新用户
文章图片
- 删除用户
文章图片
文章图片
- settings.py 配置
文件路径:mysite/settings.py
static文件夹路径:用于存放前端的一些css
、js
、icon
等文件。
AUTH_USER_MODEL:重写内置的用户管理。
DATABASES:使用的是mysql数据库,一直用的这个。
INSTALLED_APPS:新建和注册app,就不多讲了,请看之前的文章。
# mysite/settings.pyINSTALLED_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
文件,作为母版
,代码如下所示。
说明: 母版存放基本的css
和js
样式, 这样子页面就不用单独加载这些了,切记不要把所有的js或css放在一个html内,避免导致页面加载慢,按需页面加载即可。
{% loadstatic %}
{% block title %}自动化运维平台{% endblock %}
- 锐客网
{% block css %}{% endblock %}
自动化运维平台{% block page-title %} {% endblock %}
{% block page-content %} {% endblock %}{% block js %}{% endblock %}
- model配置
文件路径: mysite/users/models.py
继承内置用户系统AbstractUser
, 内置有username
、password
、email
、is_active
等字段,我在此基础上增加了cn_name
、phone
、sex
, 3个字段属性。
# mysite/users/models.py #!/usr/bin/env python3 #-*- coding:UTF-8 -*-from django.db import models from django.contrib.auth.models import AbstractUserclass 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 users
和python manage.py migrate users
- 路由url配置
文件路径:mysite/urls.py
主路由urls:
# mysite/urls.pyfrom django.contrib import admin from django.urls import path, includeurlpatterns = [ path('admin/', admin.site.urls), path('user/', include('users.urls'))# 新建 ]
子路由urls(app为users):
# mysite/users/urls.pyfrom 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
-
{% if page_obj.has_previous %}
- 首页
- 上一页 {% else %}
- 首页
- 上一页 {% endif %} {% for page in page_obj.pages %} {% if page %} {% ifequal page page_obj.number %}
- {{ page }} {% else %}
- {{ page }} {% endifequal %} {% else %}
- ... {% endif %} {% endfor %} {% if page_obj.has_next %}
- 下一页
- 尾页 {% else %}
- 下一页
- 尾页 {% endif %}
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 reclass 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.pyfrom django.views.generic import CreateView from django.contrib.messages.views import SuccessMessageMixin from django.contrib.auth import get_user_model from .form import UserModelFormUser = 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 %} {% endblock %}
? 说明:用户更新页面通过if 判断object
为true,否则就是用户添加页面了
- 效果图
文章图片
- 效果图
- 视图配置
from django.views.generic import ListView from pure_pagination.mixins import PaginationMixin from django.contrib.auth import get_user_modelUser = get_user_model()class IsActiveView(View): def post(self, request, **kwargs): pk = QueryDict(self.request.body).get('pk') value =https://www.it610.com/article/int(QueryDict(self.request.body).get('value')) try: user = User.objects.filter(id=pk) if pk and value =https://www.it610.com/article/= 1: user.update(is_active=1) res = {'code': 0, 'result': '用户激活成功!'} elif pk and value =https://www.it610.com/article/= 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 querysetdef 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 %}添加用户
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 %} 编辑 删除
{% if page_obj.paginator.num_pages > 1 %} {% include '_paginator.html' %} {% endif %} {% endblock %}{% block js %}{% endblock %}
参数解读:
- 添加用户按钮:通过页面表单方式实现用户添加;
- users:为后端
UserListView
的context_object_name
传递过来的; - 编辑按钮:和添加用户类型;
- 删除按钮:通过
ajax
的弹窗方式进行删除,没有用到页面;
- 效果图
- 视图配置
# mysite/users/views.pyfrom .form import UserModelForm from django.views.generic import UpdateView from django.contrib.auth import get_user_model from django.contrib.messages.views import SuccessMessageMixinUser = 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
类似。
- 模板配置
同用户添加
的模板一致,共用一个模板。
- 效果图
文章图片
- 视图配置
from django.views.generic import DeleteView from django.contrib.auth import get_user_modelUser = get_user_model()class UserDelView(DeleteView): """ 删除用户 """ model = Userdef 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
删除用户,参考章节用户查看
的模板文件。
- 效果图
文章图片
文章图片
CreateView
、ListView
、UpadteView
、DeleteView
都一一对应起来了,其实方法还是有很多种的。现在
用户管理
差不多就这样了,各位还可以持续去优化,做的更好,那么用户登陆认证
怎么实现呢?待我去码下一篇文章...敬请期待!
如果喜欢的我的文章,欢迎关注我的公众号:点滴技术,扫码关注,不定期分享【Django之用户管理系统CBV-全新升级(5)】
文章图片
推荐阅读
- PMSJ寻平面设计师之现代(Hyundai)
- 太平之莲
- 闲杂“细雨”
- 七年之痒之后
- 深入理解Go之generate
- 由浅入深理解AOP
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 生活随笔|好天气下的意外之喜
- 感恩之旅第75天
- python学习之|python学习之 实现QQ自动发送消息