时间过的真快,又接近4个月没更新文章了,不是我闲着,家里事情是真多,时间都给了溜娃还是溜娃,剩余点时间就学习Django
的知识,为了打磨好这一篇文章,可费了九牛二虎之力,完成该篇文章。
为了各位读者有较好的UI
视觉、有动力去学习和摸索,前端可投入不少时间。毕竟作为一名网工
,去搞前端,那还真不是一件容易的事情,你想,Django
这个后端知识体系已经够学一阵一阵子的了。
前端有啥学习?HTML、javascrip、jQuery、ajAX、Vue...
后端有啥学习?Django就够了...
说明:提前贴出这些图,希望各位看了有动力去学习。虽然django有自带一套用户系统,但是人的审美总是要有的哈,又可以提升下自己的代码水平.
用户列表展示
说明:有一些共性的东西,我就提前在这个章节写出来。
settings.py 配置 文件路径:mysite/settings.py
static文件夹路径:用于存放前端的一些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 %}
说明:用户添加的表单使用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)
参数解读:
make_password
方法生成随机的密文,默认会通过form.save()
写入数据库中。模板配置 文件路径: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,否则就是用户添加页面了
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`为传给前端搜索框内显示用的。
- 模板配置
```html
{% extends 'base1.html' %}
{% load static %}
{% block title %}
用户列表
{% endblock %}
{% block page-title %}
用户列表
{% endblock %}
{% block css %}
{% endblock %}
{% block page-content %}
UID
用户名
管理员
中文名
手机
性别
用户状态
上次登陆时间
操作
{% for user in users %}
{{ 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 %}
编辑
删除
{% endfor %}
显示 [{{ 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:为后端
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`类似。
- 模板配置
同`用户添加`的模板一致,共用一个模板。
- 效果图
![](https://img-blog.csdnimg.cn/20210815155912905.png)
## 1.5 用户删除
- 视图配置
```python
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)
总结:终于码完这篇文章了,虽然看起来就4个项目:用户的增删改查,其实一点都不容易,五味杂陈啊。我还是把CBV里的CreateView
、ListView
、UpadteView
、DeleteView
都一一对应起来了,其实方法还是有很多种的。
现在用户管理
差不多就这样了,各位还可以持续去优化,做的更好,那么用户登陆认证
怎么实现呢?待我去码下一篇文章...敬请期待!
如果喜欢的我的文章,欢迎关注我的公众号:点滴技术,扫码关注,不定期分享