Django User模型

2023-11-04

用户管理

在开发登录功能的时候需要数据库来保存用户登录信息和状态,Django中有个内置app 名为 django.contrib.auth ,缺省包含在项目Installed App设置中。

这个app 的 models 定义中包含了一张 用户表,名为 auth_user 。当执行 migrate 创建数据库表时,就创建了 用户表 auth_user ,这张用户表包含的字段有:

在这里插入图片描述

自定义用户模型

Django 内置app django.contrib.auth 已经做好了登录验证功能。如果用户表 auth_user的字段足够在项目中使用,那么直接使用默认User模型即可。

如果用户表 auth_user的字段不符合项目的需求,需要重新定义,例如需要新增一些字段,像真实姓名、手机号、用户类型等,推荐的方式是通过继承 django.contrib.auth.models 里面的 AbstractUser 类的方式。

千万不要去改 Django 内置模块 contrib.auth.models 里面的类定义,如果改动源码,那么项目就依赖当前库,如果更新了库或者环境移植重写装库,那原来的代码就失效了

models 包下新增一个 auth.py文件

from django.contrib.auth.models import AbstractUser
from django.db import models


class User(AbstractUser):
    usertype = (
        (0, '开发'),
        (1, '测试'),
        (2, '需求'),
        (3, '运维'),
    )
    realname = models.CharField(max_length=32, verbose_name='真实姓名')
    phone = models.CharField(max_length=11, unique=True, null=True, blank=True, verbose_name='手机号')
    user_tpye = models.SmallIntegerField(choices=usertype, default=0, verbose_name='用户类型')

这样就在原来的 contrib.auth 里面的 user表的基础上 新增了 usertype、realname、phone 这些字段

Django自定义验证

然后需要告诉Django,使用这个表作为 系统的 user表

models 包下的 __init__.py 文件中导入User模型

from .hr3 import Step,Case,Config,Request
from .mgr import Enviroment,Project
from .auth import User 	# 导入User模型

settings.py 文件底部,添加如下代码进行设置

AUTH_USER_MODEL = 'sqtp.User'

其中 sqtp 为定义 User 所在的 django app 名称,一定要确保这个 sqtp 在在settings.py 文件中的 INSTALLED_APPS 里面设置了。

将修改同步至数据库

python manage.py makemigrations
python manage.py migrate

可能会遇到

ValueError: The field admin.LogEntry.user was declared with a lazy reference to 'sqtp.user', but app 'sqtp' doesn't provide model 'user'.

这个错误是由于原有的用户模型被依赖,使用自定义会改变依赖关系,这个改动并不能自动完成,需要手动修复架构,将数据从旧的用户表移出,并有可能需要手动执行一些迁移操作。

由于 Django 对可交换模型的动态依赖特性的限制, AUTH_USER_MODEL 所引用的模型必须在其应用的第一次迁移中创建(通常称为 0001_initial );否则,会出现依赖问题。

所以,需要先删除migrations目录所有文件,然后再删除数据库并重写创建。再执行迁移动作就可以了。

执行迁移命令后,sqtp_user表中新增了 usertype、realname、phone 这些字段,且伴随着sqtp_user表的创建成功,会新增sqtp_user_groupssqtp_user_user_permissions两个表,一个是用户组,一个是用户权限

在这里插入图片描述

引用User模型

用户模型创建好之后,其他模型需要关联的部分就可以加上了。首先是Project,增加项目管理员admin 和成员 members,关联了同一个模型,需要设置反向查询名 related_name

如果直接引用User模型,那么以后项目改成不同的用户模型时就无法自动切到 AUTH_USER_MODEL 配置的用户模型,代码的可复用性就大打折扣了。因此应该直接引用 AUTH_USER_MODEL 配置的用户模型

mgr.py 中的项目类模型进行修改

# 存放所有项目管理相关模型

from django.db import models
from .base import CommonInfo
from django.conf import settings    # 导入setting文件中配置的内容

# 定义项目类
class Project(CommonInfo):
    Pro_Status = (
        ('developing','开发中'),
        ('operating','维护中'),
        ('stable','稳定运行中'),
        )
    # 引用 `AUTH_USER_MODEL` 配置的用户模型
    admin = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.DO_NOTHING,null=True,verbose_name='管理员',related_name='project_admin')
    members = models.ManyToManyField(settings.AUTH_USER_MODEL,verbose_name='项目成员',related_name='project_members')
    
    name = models.CharField(max_length=32,unique=True,verbose_name='项目名称')
    status = models.CharField(max_length=32,choices=Pro_Status,default='stable',verbose_name='项目状态')
    version = models.CharField(max_length=32,default='V1.0',verbose_name='版本')

    # 模型元类
    class Meta(CommonInfo.Meta): # 元类也需要显示继承父类的元类才会生效
        db_table = 'Project'  # 如果不设置,默认的名称是 app名_模型名
        verbose_name = '项目表'  # 表的对外显示名称

接下来是通用表中的创建者和更新者字段

base.py 中的公共模型进行修改

# 公共模型

from django.db import models
from django.conf import settings    # 导入setting文件中配置的内容

class CommonInfo(models.Model):
    # 公共字段部分: 创建时间、更新时间、描述
    create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间',null=True)
    # auto_now_add 第一次创建数据时自动添加当前时间
    update_time = models.DateTimeField(auto_now=True,verbose_name='更新时间',null=True)
    # auto_now 每次更新数据时自动添加当前时间
    desc = models.TextField(null=True,blank=True,verbose_name='描述')

    create_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.DO_NOTHING,null=True,verbose_name='创建者',related_name='create_member')
    update_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.DO_NOTHING,null=True,verbose_name='更新者',related_name='update_member')

    def __str__(self):
        # 判断当前数据对象是否有name属性,如果有,返回name,如果没有,返回描述
        if hasattr(self,'name'):    # hasattr 是Python中是反射的一种用法
            return self.name
        else:
            return self.desc

    class Meta:
        abstract =True  # 定义抽象表,不会创建数据库表
        ordering = ['id']  # 根据id排序(默认为顺序排序)

将修改同步至数据库

python manage.py makemigrations
python manage.py migrate

会产生报错

sqtp.Case.create_by: (fields.E304) Reverse accessor for 'sqtp.Case.create_by' clashes with reverse accessor for 'sqtp.Config.create_by'.
        HINT: Add or change a related_name argument to the definition for 'sqtp.Case.create_by' or 'sqtp.Config.create_by'.

如果在抽象基类中存在ForeignKey或者ManyToManyField字段,并且使用了 related_name 或者related_query_name 参数,那么一定要小心。因为按照默认规则,每一个子类都将拥有同样的字段,这显然会导致错误。为了解决这个问题,当在抽象基类中使用 related_name 或者 related_query_name 参数时,它们两者的值中应该包含 %(app_label)s%(class)s 部分

  • %(class)s 用字段所属子类的小写名替换
  • %(app_label)s 用子类所属app的小写名替换

父类的字段被子类继承,都使用了相同的反向查询名,者显然是不行的,所以利用 %(app_label)s%(class)s 让子类继承的字段可以自由替换反向查询名

base.py 中的公共模型进行修改

# 公共模型

from django.db import models
from django.conf import settings    # 导入setting文件中配置的内容

class CommonInfo(models.Model):
    # 公共字段部分: 创建时间、更新时间、描述
    create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间',null=True)
    # auto_now_add 第一次创建数据时自动添加当前时间
    update_time = models.DateTimeField(auto_now=True,verbose_name='更新时间',null=True)
    # auto_now 每次更新数据时自动添加当前时间
    desc = models.TextField(null=True,blank=True,verbose_name='描述')

    create_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.DO_NOTHING,null=True,verbose_name='创建者',related_name='create_member')
    update_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.DO_NOTHING,null=True,verbose_name='更新者',related_name='update_member')

    def __str__(self):
        # 判断当前数据对象是否有name属性,如果有,返回name,如果没有,返回描述
        if hasattr(self,'name'):    # hasattr 是Python中是反射的一种用法
            return self.name
        else:
            return self.desc

    class Meta:
        abstract =True  # 定义抽象表,不会创建数据库表
        ordering = ['id']  # 根据id排序(默认为顺序排序)

将修改同步至数据库

python manage.py makemigrations
python manage.py migrate

此时就可以同步成功了

视图开发

采用REST框架开发项目管理和用户管理

创建序列器

sqtp应用目录下的serializers.py文件中添加代码

from rest_framework import serializers
from sqtp.models import Config,Case,Step,Request,Enviroment,Project,User

# 项目部分序列化器
class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = '__all__'


# 环境部分序列化器
class EnviromentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = '__all__'

        
# 用户部分序列化器
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

创建视图

sqtp应用目录下的views.py文件中添加代码

from sqtp.models import Request,Case,Config,Step,Enviroment,Project     # 模型
from sqtp.serializers import RequestSerializer,CaseSerializer,StepSerializer,ConfigSerializer,EnviromentSerializer,ProjectSerializer    # 自定义的序列化类


class ProjectViewSet(viewsets.ModelViewSet):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer


class EnviromentViewSet(viewsets.ModelViewSet):
    queryset = Enviroment.objects.all()
    serializer_class = EnviromentSerializer
    
    
# 用户
@api_view(['GET'])
def user_list(request):
    query_set = User.objects.all()
    serializer = UserSerializer(query_set,many=True)
    return Response(serializer.data)


@api_view(['GET'])
def user_detail(request,_id):
    try:
        req_obj = User.objects.get(pk=_id)
    except User.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)
    serializer = UserSerializer(req_obj)
    return Response(serializer.data)

创建路由

sqtp应用目录下的urls.py文件中添加代码

router = DefaultRouter()
router.register(r'requests',sqtp_view.RequestViewSet)  
router.register(r'cases',sqtp_view.CaseViewSet)   
router.register(r'steps',sqtp_view.StepViewSet)  
router.register(r'project',sqtp_view.ProjectViewSet)  # 将Project视图信息注册路由列表
router.register(r'envs',sqtp_view.EnviromentViewSet)  # 将Enviroment视图信息注册路由列表

urlpatterns = [
    path('',include(router.urls)),
    path('swagger/',schema_view.with_ui('swagger',cache_timeout=0),name='schema-swagger-ui'),   #互动模式
    path('redoc/',schema_view.with_ui('redoc',cache_timeout=0),name='schema-redoc'),   #文档模式
    path('users/',sqtp_view.user_list),
    path('users/<int:_id>',sqtp_view.user_detail),
]

用户注册

用户认证机制的核心内容是用户模型,而用户认证机制首先要实现的就是用户注册功能–创建用户。

不同系统有不同的注册流程,但是大体上都差不都,都是提交信息给服务器,然后服务器判断没有问题后创建用户。注册流程可以参考下图

在这里插入图片描述

结合REST框架帮助我们完成验证的工作

注册序列化器

sqtp应用目录下的serializers.py文件中新增注册序列化器

# 注册序列化器
class RegisrerSerializer(serializers.ModelSerializer):
    # admin_code 不在User字段中,需要单独定义
    admin_code = serializers.CharField(default='')
    class Meta:
        model = User
        fields = ['username','password','email','phone','realname','admin_code']

    # 校验入参是否合法
    def validate(self, attrs):  # attrs为入参的字典形式
        if attrs.get('admin_code') and attrs['admin_code'] != 'sqtp_code':
            raise ValidationError('错误的admin_code')
        return attrs

    # 重写序列化器的保存方法
    def register(self):
        # 入参内容
        in_param = self.data
        # 入参内容是否有传 admin_code
        if 'admin_code' in in_param and in_param['admin_code'] == 'sqtp_code':
            in_param.pop('admin_code')  # 创建用户数据不需要admin_code,校验通过即可,需要将这个数据剔除出去
            # 创建管理员
            user = User.objects.create_superuser(**in_param) # 将数据进行解包,创建管理员
        else:
            in_param.pop('admin_code')
            user = User.objects.create_user(**in_param) # 将数据进行解包,创建普通用户
        return user

注册视图

sqtp应用目录下的views.py文件中新增注册视图

from sqtp.serializers import RequestSerializer, CaseSerializer, StepSerializer, ConfigSerializer, EnviromentSerializer, \
    ProjectSerializer, UserSerializer, RegisrerSerializer  # 自定义的序列化类
from django.contrib import auth     # 导入django自带的auth模块

@api_view(['POST'])
def register(request):
    # 获取序列化器
    serializer = RegisrerSerializer(data=request.data)
    if serializer.is_valid():    #自动根据模型定义来判断数据入参是否合法
        user = serializer.register()    # 创建用户数据
        auth.login(request,user)    # 完成用户登录状态的设置
        return Response(data={'msg':'register success','is_admin':user.is_superuser,'retcode':status.HTTP_201_CREATED},status=status.HTTP_201_CREATED)
    return Response(data={'msg':'error','retcode':status.HTTP_400_BAD_REQUEST,'error':serializer.errors},status=status.HTTP_400_BAD_REQUEST)
    

注册路由

sqtp应用目录下的urls.py文件中新增路由

urlpatterns = [
    path('',include(router.urls)),
    path('swagger/',schema_view.with_ui('swagger',cache_timeout=0),name='schema-swagger-ui'),   #互动模式
    path('redoc/',schema_view.with_ui('redoc',cache_timeout=0),name='schema-redoc'),   #文档模式
    path('users/',sqtp_view.user_list),
    path('users/<int:_id>',sqtp_view.user_detail),
    path('register/',sqtp_view.register),   # 注册
]

在浏览器中输入http://127.0.0.1:8888/register.html,进入注册页面,输入注册信息创建账户

在这里插入图片描述

可以看到数据库sqtp_user表中新增了一条用户数据

用户登录

登录流程如下图所示,同样数据验证部分可以写进序列化器中

登录序列化器

与注册不同的是,登录不需要默认的序列化器校验数据,因为登录使用的是已有的数据,因此应该序列号其调用validate方法返回验证后的user对象即可

sqtp应用目录下的serializers.py文件中新增登录序列化器

# 登录序列化器
class LoginSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username','password']

    def validate(self, attrs):
        # 检查必填参数
        position_params = ['username','password']
        for param in position_params:
            if param not in attrs:
                raise ValidationError(f'缺少参数:{param}')
        # 验证用户名和密码
        user = auth.authenticate(**attrs)
        if not user:
            raise ValidationError('用户名或密码错误')
        return user

登录视图

sqtp应用目录下的views.py文件中新增登录视图

@api_view(['POST'])
def login(request):
    # 获取登录信息--序列化器
    serializer = LoginSerializer(data=request.data)
    user = serializer.validate(request.data)
    if user:
        auth.login(request,user)    # 登录存储session信息
        return Response(data={'msg':'login success','to':'index.html'},status=status.HTTP_302_FOUND)    # 登录成功后页面重定向到index页面
    return Response(data={'msg': 'error', 'retcode': status.HTTP_400_BAD_REQUEST, 'error': serializer.errors},status=status.HTTP_400_BAD_REQUEST)   # 失败返回错误信息

登录路由

sqtp应用目录下的urls.py文件中新增路由

urlpatterns = [
    path('',include(router.urls)),
    path('swagger/',schema_view.with_ui('swagger',cache_timeout=0),name='schema-swagger-ui'),   #互动模式
    path('redoc/',schema_view.with_ui('redoc',cache_timeout=0),name='schema-redoc'),   #文档模式
    path('users/',sqtp_view.user_list),
    path('users/<int:_id>',sqtp_view.user_detail),
    path('register/',sqtp_view.register),   # 注册
    path('login/',sqtp_view.login),   # 登录
]

在浏览器中输入http://127.0.0.1:8888/login.html,进入登录页面,输入注册信息账户的账号和密码,登录成功后会跳转到index首页

用户登出

这个比较简单,没有请求参数,范围对应的视图就可以完成登出流程,因此无需序列化器

登出视图

sqtp应用目录下的views.py文件中新增登出视图

@api_view(['GET'])
def logout(request):
    # 当前用户处于登录状态
    if request.user.is_authenticated:
        auth.logout(request)    # 清除登录信息
    return Response(data={'msg': 'logout', 'to': 'login.html'},status=status.HTTP_302_FOUND)    # 重定向到登录页面

登出路由

sqtp应用目录下的urls.py文件中新增路由

urlpatterns = [
    path('',include(router.urls)),
    path('swagger/',schema_view.with_ui('swagger',cache_timeout=0),name='schema-swagger-ui'),   #互动模式
    path('redoc/',schema_view.with_ui('redoc',cache_timeout=0),name='schema-redoc'),   #文档模式
    path('users/',sqtp_view.user_list),
    path('users/<int:_id>',sqtp_view.user_detail),
    path('register/',sqtp_view.register),   # 注册
    path('login/',sqtp_view.login),   # 登录
    path('logout/',sqtp_view.logout),   # 登出
]

点击右上角头像,进行退出操作,可以发现页面重定向到登录页面

获取当前用户信息视图

前后端分离的系统前端部分需要同步后端的访问状态,因此构造一个请求用于检查是否登录,这样在切换页面时可以根据当前用户状态选择是否重定向到登录界面。

sqtp应用目录下的views.py文件中新增获取当前用户信息视图,用于跑马灯,以及前端判断当前用户是否登录的依据

@api_view(['GET'])
def current_user(request):
    # 如果当前用户处于登录状态
    if request.user.is_authenticated:
        serializer = UserSerializer(request.user)
        # 返回当前用户信息
        return Response(data=serializer.data)
    else:
        return Response(data={'msg': '用户未登录', 'retcode': status.HTTP_403_FORBIDDEN, 'to': 'login.html'},status=status.HTTP_403_FORBIDDEN)   # 重定向到登录页面

sqtp应用目录下的urls.py文件中新增路由

urlpatterns = [
    path('',include(router.urls)),
    path('swagger/',schema_view.with_ui('swagger',cache_timeout=0),name='schema-swagger-ui'),   #互动模式
    path('redoc/',schema_view.with_ui('redoc',cache_timeout=0),name='schema-redoc'),   #文档模式
    path('users/',sqtp_view.user_list),
    path('users/<int:_id>',sqtp_view.user_detail),
    path('register/',sqtp_view.register),   # 注册
    path('login/',sqtp_view.login),   # 登录
    path('logout/',sqtp_view.logout),   # 登出
    path('current_user/',sqtp_view.current_user),   # 获取当前用户信息视图
]

该视图的作用仅作为前后端交互中前端判断当前用户是否登录的依据,但是并未做到权限校验,通过swagger还是可以通过接口获取信息

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django User模型 的相关文章

随机推荐

  • 【分布式】红包秒杀系统、高并发安全分布式锁

    分布式 内容管理 业务Intro 业务模块划分 数据库表设计 开发流程 红包金额随机生成算法 Monte Carlo 方法 发红包模块 EnableAsync 多线程异步 抢红包模块 并发测试 Jmeter压力测试高并发下抢红包 并发安全问
  • python之面向对象编程

    最近阅读到了一篇关于面向对象编程和面向过程编程解释说明的文章 觉得写的通俗易懂 文章链接如下 漫画 如何通俗易懂地解释面向对象思想 但是该文章举的例子是用Java 故在此我按照我的理解 针对python 梳理一下面向对象编程 一 面向对象编
  • 微信小程序image组件的使用

    image属性说明 属性 类型 默认值 必填 说明 src string 否 图片资源地址 mode string scaleToFill 否 图片裁剪 缩放的模式 webp string false 否 默认不解析 webP 格式 只支持
  • java 生成excel下载_java生成excel并下载功能

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 HttpServletRequest request ServletActionContext getRequest projectId long Integer parseInt reques
  • 奇安信和深信服哪个好_网络安全头部公司全面比较

    管理 网络安全头部公司全面比较 秋名山藤原 2019 06 10 08 47 发布 选取的样本包括启明星辰 绿盟科技 奇安信 天融信 深信服 本人很看好的公司安恒信息还在静默期 就不写了 后面上市了再统一到一个表里面 关于下表有几点说明 基
  • 微电网优化调度(风、光、储能、柴油机)(Python代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 目录 1 概述 2 运行结果 3 参考文献 4 Python代码实现 详细文章 数据 文献来源 Python代码复现之 1 概述 电力对
  • Spring框架(四)Spring的Bean作用域和生命周期

    目录 一 作用域定义 二 同 类型多个 Bean 报错的解决办法 三 Bean的6种作用域 1 singleton 单例作用域 2 prototype 原型作用域 多例作用域 3 request 请求作用域 4 session 回话作用域
  • qsort的函数的使用。

    目录 一 qsort函数的定义 二 qsort的应用 1 比较数字大小 2 比较结构体类型 1 基于年龄排序 2 基于名字排序 三 基于冒泡函数自定义qsort函数 编辑 一 qsort函数的定义 使用qsort函数要加上头文件 inclu
  • 车载测试面试题,进军车企必看

    随着新能源汽车的普及 相关产业也会越来越多 很多车企都开始做 自动驾驶 了 例如 奔驰 宝马 奥迪 沃尔沃 比亚迪等等都已经开始启动 在未来 中国智能网联汽车产业将迎来爆发式增长 今天给大家分享一波车载测试相关面试题 准备进军车企的朋友可以
  • Redis3.0的主从、集群高可用

    1 安装Redis3 0 yum y install cpp binutils glibc glibc kernheaders glibc common glibc devel gcc make gcc c libstdc devel tc
  • 使用Nodejs搭建HTTP服务,并实现公网远程访问Redis数据库「内网穿透」

    文章目录 1 Linux centos8 安装redis数据库 2 配置redis数据库 3 内网穿透 3 1 安装cpolar内网穿透 3 2 创建隧道映射本地端口 4 配置固定TCP端口地址 4 1 保留一个固定tcp地址 4 2 配置
  • AI大模型及算力要求

    AI大模型对算力的要求非常高 需要高性能的硬件设备和分布式训练技术来支持 随着AI技术的不断发展 未来可能会出现更大 更复杂的模型 对算力的要求也将更高 今天和大家分享几个大模型及算力要求 希望对大家有所帮助 北京木奇移动技术有限公司 专业
  • markdown公式编号居右

  • .NET5零基础入门到项目实战(源码+课件),2021年最新版

    本套课程来自朝夕教育 NET5零基础入门到项目实战 源码 课件 课程由Richard老师 朝夕教育 Eleven Clay老师联合主讲 课程为2021年最新版视频课程 共60节 包含课程相关资料源码 共计4 1G 文章底部附下载地址 课程介
  • 优化算法 - Adadelta

    文章目录 Adadelta 1 Adadelta算法 2 代码实现 3 小结 Adadelta Adadelta是AdaGrad的另一种变体 主要区别在于前者减少了学习率适应坐标的数量 此外 广义上Adadelta被称为没有学习率 因为它使
  • pysot环境 win10 cuda10.1、torch

    1 安装anaconda 版本 Anaconda3 2019 07 python 3 7 3 跟踪Python版本对应找到Anaconda3对应版本 参考 anaconda python 版本对应关系 茶佬牛逼 CSDN博客 python3
  • 学生成绩管理系统mysql课程设计_数据库课程设计报告-学生成绩管理系统

    数据库课程设计报告 学生成绩管理系统 引 言 在现代 高科技的飞跃发展 计算机的大量普及 使得人们生活节奏越来越快 因此对教育行业的多元信息进行有效的管理工作 也成为教育行业中的重中之重 目前 学校工作繁杂 资料重多 虽然各类管理信息系统已
  • 导入自定义模块syntaxerror: invalid syntax_乐高机器人

    模块功能讲解 只剩下高级模块和自定义模块未做说明了 今天一起讲完 了解了模块的功能之后 需要通过实际的运用才能知道不同模块的功能差异 下期谈谈几个实际应用的案例 一 高级模块 一 文件读写 这个模块的功能在于将运行过程中产生的数据存储到EV
  • Linux系统安装部署Tomcat(超详细操作演示)

    Tomcat安装部署 Linux 简介 第一步 安装JDK环境 第二步 解压并部署Tomcat 简介 Tomcat 是由 Apache 开发的一个 Servlet 容器 实现了对 Servlet 和 JSP 的支持 并提供了作为Web服务器
  • Django User模型

    Django User模型 用户管理 自定义用户模型 Django自定义验证 引用User模型 视图开发 创建序列器 创建视图 创建路由 用户注册 注册序列化器 注册视图 注册路由 用户登录 登录序列化器 登录视图 登录路由 用户登出 登出