时间过的真快,又接近4个月没更新文章了,不是我闲着,家里事情是真多,时间都给了溜娃还是溜娃,剩余点时间就学习Django
的知识,为了打磨好这一篇文章,可费了九牛二虎之力,完成该篇文章。
为了各位读者有较好的UI
视觉、有动力去学习和摸索,前端可投入不少时间。毕竟作为一名网工
,去搞前端,那还真不是一件容易的事情,你想,Django
这个后端知识体系已经够学一阵一阵子的了。
前端有啥学习?HTML、javascrip、jQuery、ajAX、Vue...
后端有啥学习?Django就够了...
1.0 效果展示
说明:提前贴出这些图,希望各位看了有动力去学习。虽然django有自带一套用户系统,但是人的审美总是要有的哈,又可以提升下自己的代码水平.
用户列表展示
1.1 基础配置
说明:有一些共性的东西,我就提前在这个章节写出来。
settings.py 配置
文件路径:mysite/settings.pystatic文件夹路径:用于存放前端的一些
css
、js
、icon
等文件。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
文件,作为母版
,代码如下所示。说明: 母版存放基本的
css
和js
样式, 这样子页面就不用单独加载这些了,切记不要把所有的js或css放在一个html内,避免导致页面加载慢,按需页面加载即可。
{% load static %}
{% 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 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 users
和python 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
-
{% 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 %}
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 }}
说明:用户更新页面通过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 %}
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 %}参数解读:
- 添加用户按钮:通过页面表单方式实现用户添加;
- users:为后端
UserListView
的context_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里的CreateView
、ListView
、UpadteView
、DeleteView
都一一对应起来了,其实方法还是有很多种的。
现在用户管理
差不多就这样了,各位还可以持续去优化,做的更好,那么用户登陆认证
怎么实现呢?待我去码下一篇文章...敬请期待!
如果喜欢的我的文章,欢迎关注我的公众号:点滴技术,扫码关注,不定期分享