内容简介:新建一个app, 名称叫system包含用户管理、菜单管理和权限管理等系统基础模块。sandboxMP项目使用的是自定义权限认证模型,模型说明:下面内容就是权限认证的模型详细内容,将如下内容复制到apps/system/models.py
新建一个app, 名称叫system包含用户管理、菜单管理和权限管理等系统基础模块。
- 使用pycharm打开我们的项目,右键项目根目录,选择 New → Python Package, 在弹出的窗口输入apps,这个包就用来存放项目中创建的所有app.
- 选择pycharm上方Tools,点击Runmanage.py Task..., 这时在pycharm下方会打开一个窗口,输入startapp system 回车创建app, 如下图:
- 将刚刚创建的system 移动到 apps下
- 为了能够顺利访问到我们新建的app,右键apps,选择Mark Directory as → Sources root
- 修改sandboxMP/sandboxMP/settings.py 加入如下内容:
import sys sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) 复制代码
1.2 创建权限认证模型
sandboxMP项目使用的是自定义权限认证模型,模型说明:
Menu: 菜单管理,用来存储系统可用的URL Role: 角色组,通过外键关联Menu,角色组中的用户将继承Role关联菜单的访问权限 Structure:组织架构,包含单位和部门信息 UserProfile: 自定义用户认证模型,替换系统原有的User模型 复制代码
下面内容就是权限认证的模型详细内容,将如下内容复制到apps/system/models.py
from django.db import models from django.contrib.auth.models import AbstractUser class Menu(models.Model): """ 菜单 """ name = models.CharField(max_length=30, unique=True, verbose_name="菜单名") # unique=True, 这个字段在表中必须有唯一值. parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="父菜单") icon = models.CharField(max_length=50, null=True, blank=True, verbose_name="图标") code = models.CharField(max_length=50, null=True, blank=True, verbose_name="编码") url = models.CharField(max_length=128, unique=True, null=True, blank=True) def __str__(self): return self.name class Meta: verbose_name = '菜单' verbose_name_plural = verbose_name @classmethod def get_menu_by_request_url(cls, url): return dict(menu=Menu.objects.get(url=url)) class Role(models.Model): """ 角色:用于权限绑定 """ name = models.CharField(max_length=32, unique=True, verbose_name="角色") permissions = models.ManyToManyField("menu", blank=True, verbose_name="URL授权") desc = models.CharField(max_length=50, blank=True, null=True, verbose_name="描述") class Structure(models.Model): """ 组织架构 """ type_choices = (("unit", "单位"), ("department", "部门")) name = models.CharField(max_length=60, verbose_name="名称") type = models.CharField(max_length=20, choices=type_choices, default="department", verbose_name="类型") parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="父类架构") class Meta: verbose_name = "组织架构" verbose_name_plural = verbose_name def __str__(self): return self.name class UserProfile(AbstractUser): name = models.CharField(max_length=20, default="", verbose_name="姓名") birthday = models.DateField(null=True, blank=True, verbose_name="出生日期") gender = models.CharField(max_length=10, choices=(("male", "男"), ("female", "女")), default="male", verbose_name="性别") mobile = models.CharField(max_length=11, default="", verbose_name="手机号码") email = models.EmailField(max_length=50, verbose_name="邮箱") image = models.ImageField(upload_to="image/%Y/%m", default="image/default.jpg", max_length=100, null=True, blank=True) department = models.ForeignKey("Structure", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="部门") post = models.CharField(max_length=50, null=True, blank=True, verbose_name="职位") superior = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="上级主管") roles = models.ManyToManyField("role", verbose_name="角色", blank=True) class Meta: verbose_name = "用户信息" verbose_name_plural = verbose_name ordering = ['id'] def __str__(self): return self.name 复制代码
1.3 使用模型
定义好模型后,还要告诉Django使用这些模型,我们需要修改settings.py文件,在INSTALLED_APPS中添加models.py所在应用的名称:
INSTALLED_APPS = [ ...原内容省略... 'system', ] 复制代码
想要使用自定义的认证模型UserProfile, 还需要在setting.py中添加下面内容:
AUTH_USER_MODEL = 'system.UserProfile' 复制代码
注意:
在定义用户模型的时候使用到了ImageField字段类型,在执行makemigrations前需要安装依赖包:pillow,打开CMD窗口,进入本项目的 python 虚拟环境,然后安装pillow:
C:\Users\RobbieHan>workon sandboxMP (sandboxMP) C:\Users\RobbieHan>pip install pillow 复制代码
也可以在pycharm 的Terminal终端窗口执行安装命令: pip install pillow
最后执行makemigrations 和 migrate来生成数据表, 使用pycharm Tools,点击Runmanage.py Task..., 在manage.py窗口输入下面命令:
makemigrations migrate 复制代码
1.4 模型(Models)相关知识点
字段类型:
在权限认证模型中使用到的字段类型如下:
CharField: 用来存储字符串,必须制定一个参数 max_length用来限定字段最大长度 Foreignkey: 是一个关联字段,创建多表之间的多对一关系,如果创建同表之间的递归关联关系,可以使用models.ForeignKey('self') ManyToManyField: 用来实现多对多的关联关系 DateField: 日期时间字段 EmailField: email字段,用来检查email地址是否合法 ImageField: 图片字段,用来定义图片上传和图片检查,需要安装pillow库 复制代码
字段选项:
unique: 设置为True, 则表示这个字段必须有唯一值,这是从数据库级别来强制数据唯一,后面我们还会介绍通过form验证来确保数据输入的唯一 verbose_name: blank: 默认值是False, 设置为True,则该字段润许为空 null: 默认值是False,如果为True,Django会在数据库中将空值转存为NULL choices: 是一个可迭代结构(元祖),每个元组中的第一个元素,是存储在数据库中的值;第二个元素是使人容易理解的描述。 复制代码
on_delete :在django2.0版本以前,定关联字段时,on_delete选项并不是必须的,而在django2.0版本后,在定义关联字段时on_delete是必须要定义的,常用参数如下:
on_delete=models.CASCADE, # 删除关联数据,与之关联也删除 on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做 on_delete=models.PROTECT, # 删除关联数据,引发错误ProtectedError on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值 复制代码
需要注意的是在使用SET_NULL的时候,该字段在模型定义的时候需要设置可为空,例如:
user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True) 复制代码
同样在使用SET_DEFAULT的时候,需要预先定义default:
user = models.ForeignKey(User, on_delete=models.SET_DEFAULT, default='默认值') 复制代码
更多字段类型和字段选项请参考:
docs.djangoproject.com/en/1.11/ref…2 用户认证和访问限制
用户登录认证的需求如下:
- 用户登陆系统才可以访问某些页面,
- 如果用户没有登陆而直接访问就会跳转到登陆界面,
- 用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址,
- 用户可以使用用户名、手机号码或者其他字段作为登陆用户名。
在pycharm中,选中sandboxMP/apps/system,右键,选择 New → Python File, 在弹出的窗口输入名称:views_user,在刚创建的页面中导入需要的模块:
from django.shortcuts import render from django.views.generic.base import View from django.http import HttpResponseRedirect from django.contrib.auth import authenticate, login, logout from django.urls import reverse 复制代码
说明: 以下创建的视图,都是写在sandboxMP/apps/system/views_user.py文件中
2.1 创建index页面视图
index页面视图,是本项目创建的第一个视图:
class IndexView(View): def get(self, request): return render(request, 'index.html') 复制代码
知识点介绍:
1、视图:Django官方文档对“视图”的介绍是用来封装处理用户请求和返回响应的逻辑。
我们可以定义视图函数,用来接受Web请求并返回Web响应,也可以使用基于类的视图对象,本项目的视图实现都是基于类创建的视图,和基于函数的视图相比据有一定的区别和优势:
- 可以通过单独的方法编写与HTTP方法相关的代码(GET, POST等),无需通过条件分支来判断HTTP方法
- 可将代码分解成可重用的组件,例如Mixin(多继承),发挥面向对象技术优势,使用更加灵活,易于扩展
2、render函数:Django的快捷函数,结合给定的模板和一个给定的上下文字典,并返回一个选然后的HttpRespose对象,语法:render(request, template_name, context=None, content_type=None, status=None, using=None),其中 request 和template_name必须参数,其它为可选参数。
2.2 创建用户登陆视图
在创建用户登陆视图前,先创建一个sandboxMP/apps/system/forms.py文件,用来做登陆用户的输入验证,内容如下:
from django import forms class LoginForm(forms.Form): username = forms.CharField(required=True, error_messages={"requeired": "请填写用户名"}) password = forms.CharField(required=True, error_messages={"requeired": "请填写密码"}) 复制代码
创建用户登陆视图:
from .forms import LoginForm class LoginView(View): def get(self, request): if not request.user.is_authenticated: return render(request, 'system/users/login.html') else: return HttpResponseRedirect('/') def post(self, request): redirect_to = request.GET.get('next', '/') login_form = LoginForm(request.POST) ret = dict(login_form=login_form) if login_form.is_valid(): user_name = request.POST['username'] pass_word = request.POST['password'] user = authenticate(username=user_name, password=pass_word) if user is not None: if user.is_active: login(request, user) return HttpResponseRedirect(redirect_to) else: ret['msg'] = '用户未激活!' else: ret['msg'] = '用户名或密码错误!' else: ret['msg'] = '用户和密码不能为空!' return render(request, 'system/users/login.html', ret) 复制代码
Django使用会话和中间件来拦截认证系统中的请求对象。它们在每一个请求上提供一个request.user属性,表示当前的用户。如果当前的用户没有登入,该属性将设置成AnonymousUser的一个实例,否则将会是User实例。
1、request.user.is_authenticated:用来判断用户是否登入,如LoginView中:
# 当用户访问登陆页面时,判断用户如果未登入则访问登陆页面,如果登入则跳转到首页 if not request.user.is_authenticated: return render(request, 'system/users/login.html') else: return HttpResponseRedirect('/') 复制代码
2、is_valid():Form实力的一个方法,用来做字段验证,当输入字段值合法时,它将返回True,同时将表单的数据存放到cleaned_data属性中。
3、authenticate(request=None, **credentials):用来认证用户,credentials为关键字参数,默认为username和password,如果通过认证后端检查,则返回一个User对象。
4、login(request, user, backend=None):用来从视图中登陆一个用户,同时将用户的ID保存在session表中。注意:在调用login()之前必须使用authenticate()成功认证这个用户。
5、HttpResponseRedirect[source]:用来重定向访问,参数是重定向的地址,可以是完整的URL,也可以相想读与项目的绝对路径。
2.3 创建用户登出视图
class LogoutView(View): def get(self, request): logout(request) return HttpResponseRedirect(reverse('login')) 复制代码
1、logout(request):登出用户。
2、reverse(viewname):根据url name来进行url的反向解析。
2.4 配置用户URL路由
想要通过URL来访问视图应用,还需要配置URL路由,修改sandboxMP/sandboxMP/urls.py:
from django.contrib import admin from django.urls import path from system.views_user import IndexView, LoginView, LogoutView urlpatterns = [ path('admin/', admin.site.urls), path('', IndexView.as_view(), name='index'), path('login/', LoginView.as_view(), name='login'), path('logout/', LogoutView.as_view(), name='logout'), ] 复制代码
2.5 创建认证用户
在pycharm选择 Tools,点击Runmanage.py Task..., 在打开的窗口中输入createsuperuser,根据提示输入用户名,邮箱和密码,操作过程如下:
manage.py@sandboxMP > createsuperuser "C:\Program Files\JetBrains\PyCharm2017.3.2\bin\runnerw.exe" C:\Users\RobbieHan\Envs\sandboxMP\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm2017.3.2\helpers\pycharm\django_manage.py" createsuperuser D:/ProjectFile/sandboxMP 用户名: admin 邮箱: robbie_han@outlook.com Warning: Password input may be echoed. Password: !qaz@wsx Warning: Password input may be echoed. Password (again): !qaz@wsx Superuser created successfully. 复制代码
运行项目,访问系统: http://127.0.0.1:8000 ,我们并没有登入用户,直接可以访问首页,这和我们的要求不符。接下来实现页面访问限制,要求必须登入用户才能访问。
2.6 页面访问限制
页面访问限制的实现需求:
- 用户登录系统才可以访问某些页面
- 如果用户没有登陆而直接访问就会跳转到登陆界面
- 用户在跳转的登陆页面完成登陆后,自动访问跳转前的访问地址
新建sandboxMP/apps/system/mixin.py,写入如下内容:
from django.contrib.auth.decorators import login_required class LoginRequiredMixin(object): @classmethod def as_view(cls, **init_kwargs): view = super(LoginRequiredMixin, cls).as_view(**init_kwargs) return login_required(view) 复制代码
修改sandboxMP/sandboxMP/settings.py, 加入LOGIN_URL
LOGIN_URL = '/login/' 复制代码
需要登入用户才能访问的视图,只需要继承LoginRequiredMixin即可,修改后的IndexView视图如下:
from .mixin import LoginRequiredMixin class IndexView(LoginRequiredMixin, View): def get(self, request): return render(request, 'index.html') 复制代码
注意:LoginRequiredMixin位于继承列表最左侧位置
重启项目,我们再次访问首页,打开浏览器,输入http://127.0.0.1:8000,这时我们会发现,浏览器中的URL会变成: http://127.0.0.1:8000/login/?next=/, 需要我们先登陆后才会跳转到首页。
使用我们在2.5小节中创建的用户:admin,密码: !qaz@wsx登陆系统
2.7 媒体文件的访问
尽管在创建用户时设置了默认头像,并且已经放置了默认头像使用的图片,但是用户登录后还是无法显示头像,所以还需要配置媒体文件的访问。
媒体文件是由用户上传的文件,路径是变化的,比如用户上传的头像文件。
设置文件上传目录
修改sandboxMP/sandboxMP/settings.py文件,添加如下配置:
MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 复制代码
打开sandboxMP/sandboxMP/urls.py,新增如下配置:
from django.conf import settings from django.urls import re_path from django.views.static import serve if settings.DEBUG: urlpatterns += [ re_path(r'^media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}), ] 复制代码
刷新页面就可以看到用户头像了,需要注意的是,这里之所以使用if settings.DEBUG,是因为这种配置模式应该仅限用于开发模式,在生产环境应该通过web前端来处理这些媒体文件的访问。
最新最全文档发布在知识星球,可以通过微信搜索公众号“知识星球”,直接回复"52824366"获得访问入口
本节文档对应源码版本: github.com/RobbieHan/s…
非常欢迎感兴趣的朋友,到我的Github或掘金上做客,闲暇之余给个赞或Star,赠人玫瑰手留余香
文档配套项目地址: github.com/RobbieHan/s…
轻量级办公管理系统项目开源地址: github.com/RobbieHan/g…
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Nacos 权限控制介绍及实战
- 案例演示:ToB领域的权限体系实战
- kotlin协程实战:用协程实现动态权限请求
- Django框架–权限代码+左侧菜单和权限应用
- 同等权限下多任职之间数据权限的实例
- 在 Windows 系统上降低 UAC 权限运行程序(从管理员权限降权到普通用户权限)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Haskell School of Music
Paul Hudak、Donya Quick / Cambridge University Press / 2018-10-4 / GBP 42.99
This book teaches functional programming through creative applications in music and sound synthesis. Readers will learn the Haskell programming language and explore numerous ways to create music and d......一起来看看 《The Haskell School of Music》 这本书的介绍吧!