搜索
简帛阁>技术文章>django入门(四)

django入门(四)

免费分享,平时搬砖,周末会录制匹配的视频。
配套视频地址:https://www.bilibili.com/video/BV1eQ4y1U7os/
当你想要放弃的时候,想想当初为什么坚持到了现在!!!
新建项目

django项目搭建

新建应用users模块,如下:

方便测试,打开users应用的models新建user model类:

from django.db import models


# Create your models here.


class Users(models.Model):
    STATUS_CHOICES = (  # 数据库存储为0跟1 待会查询出来的时候,对象就会替换为后面的value
        (0, '正常'),
        (1, '冻结')
    )
    name = models.CharField(max_length=20, verbose_name='姓名')
    status = models.SmallIntegerField(choices=STATUS_CHOICES, default=0, verbose_name='状态')
    username = models.CharField(max_length=200, null=False, verbose_name='用户名')
    password = models.CharField(max_length=200, null=False, verbose_name='密码')
    phone = models.CharField(max_length=11, verbose_name='电话')
    email = models.CharField(max_length=50, verbose_name="邮箱")
    dept = models.IntegerField(null=False, verbose_name='部门编号')
    integral = models.IntegerField(null=False, verbose_name='积分')

    class Meta:
        db_table = 'users'
        verbose_name = '用户表'

    def __str__(self):
        return '用户姓名:%s,用户名:%s' % (self.name, self.username)

安装mysqlclient,修改settings的数据库配置,然后进行数据库迁移(请参考django项目搭建)

插入一条测试数据:

INSERT INTO users VALUES(1,'重楼','0','admin','123456','13011111111','666@qq.com',1,50)

1.django view

1.1通过view实现接口访问

​ 编写users下面的views.py

from django.forms import model_to_dict
from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from .models import Users

# 继承View
class user_view(View):
    # username: restfull风格根据用户名查询用户信息
    # get请求会自动进入get方法
    def get(self, request, username):
        user = Users.objects.get(username=username)
        result_dict = {<!-- -->
            'code': 200,
            'msg': '查询成功',
            # 将model转换为字典
            'data': model_to_dict(user)
        }
        return JsonResponse(result_dict, safe=False)

users下面的urls.py:

from django.urls import path, re_path, include
# 导入user_view
from .views import user_view

urlpatterns = [
    # <username> 等于 <str:username> 表示传递字符串   在view层用username获取
    path('user/<username>/', user_view.as_view(), name='getUserByUsername')
]

项目总路由,urls.py

from django.contrib import admin
from django.urls import path, re_path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^', include(('users.urls', 'users'), namespace='users'))
]

启动项目 访问http://localhost:8000/user/admin/ 即可看到结果

1.2为什么get请求就能进入get方法 post请求就进入post方法呢

打开view源码,

所以get请求就能进入get方法,post就能进入post其它类似

也可以重写dispatch方法来增加前后逻辑:

1.3其它view

在django中 把这种继承于view的编写方式称为 CBV,之前通过方法访问的方式称为FBV

除了view以为还有templateView ListView 大家可以自行学习,因为我开发中未使用,我做的真实项目采用vue+python的前后端分离模式.后面视频讲解的项目也是前后端分离模式

2.django拦截器

Django的middleware的概念相当于java框架里面的filter/interceptor的概念。中间键的作用就是对所有的request,在request前,和在response后做一定的处理。

请求(Request)中间件->对应函数process_request
视图(View)中间件->对应函数process_view
模板(Template)中间件->对应函数process_template_response(不常用)
响应(Response)中间件->对应函数process_response
异常(Exception)中间件->对应函数process_exception(不常用)

2.1.编写拦截器

在users应用下面添加 interceptor.py

from django.http import JsonResponse
from django.utils.deprecation import MiddlewareMixin


class a(MiddlewareMixin):
    def process_request(self, request):
        print("A request")
        # 如果这里返回 HttpResponse或者JsonResponse 那么不会访问对应的view了 直接结束返回给前端
        # return JsonResponse({"code": "401", "msg": "请先登录"}, safe=False)

    def process_response(self, request, response):
        print('A response')
        return response


class b(MiddlewareMixin):
    def process_request(self, request):
        print("b request")

    def process_response(self, request, response):
        print('b response')
        return response

2.2注册拦截器

setting里面:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'users.interceptor.a',   # 我的应用是users  interceptor是文件名  a/b是方法名
    'users.interceptor.b',
]

启动访问1.3中的http://localhost:8000/user/admin/ 结果是

A request
b request
before
get方法被调用...
after
b response
A response

如何结束拦截器 上面有注释

django过滤器跟模板相关,前后端分离不需要模板,这里不做讨论。

3.django redis操作

3.1redis安装

考虑到有的同学对redis安装不熟悉 这里提高windows版本的redis ,解压即可使用,最好别放在中文目录下。后续标准的redis环境在项目中搭建

链接:https://pan.baidu.com/s/1LBqIJA2M3f-2T0tA7-8klQ 
提取码:jf2x 
--来自百度网盘超级会员V5的分享

3.2django配置redis

安装

pip install redis==3.2.1 -i  https://pypi.douban.com/simple

pip install django-redis==5.0.0 -i  https://pypi.douban.com/simple

setting.py 配置

# Redis缓存库配置
CACHES = {<!-- -->
    "default": {<!-- -->
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/0",
        "OPTIONS": {<!-- -->
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor",
            "CONNECTION_POOL_KWARGS": {<!-- -->"max_connections": 512},
            "IGNORE_EXCEPTIONS": True,
            "SOCKET_CONNECT_TIMEOUT": 5,  # in seconds
            "SOCKET_TIMEOUT": 5,  # in seconds
        }
    },
    "redis2": {<!-- -->
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {<!-- -->
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor",
            "CONNECTION_POOL_KWARGS": {<!-- -->"max_connections": 512},
            "IGNORE_EXCEPTIONS": True,
            "SOCKET_CONNECT_TIMEOUT": 5,  # in seconds
            "SOCKET_TIMEOUT": 5,  # in seconds
        }
    },
}

3.3在shell中使用

3.4redis工具类封装

from django_redis import get_redis_connection


def query_cache():
    """
        根据settings.py 里面配置的名称获取连接池 这里以redis2为例
    """
    conn_redis = get_redis_connection("redis2")
    return conn_redis


class RedisUtils():
    """
        redis String类型操作
    """

    @staticmethod  # 直接
    def get(key, default=None):
        cache = query_cache()
        value = cache.get(key)
        if value is None:
            return default
        return value
    """普通的设置值"""
    @staticmethod
    def set(key, value):
        cache = query_cache()
        cache.set(key, value)
    """timeout:设置过期时间 单位秒"""
    @staticmethod
    def set(key, value, timeout):
        cache = query_cache()
        cache.set(key, value, timeout)
    """获得key的过期时间"""
    @staticmethod
    def ttl(key):
        cache = query_cache()
        return cache.ttl(key)
    """设置key的过期时间"""
    @staticmethod
    def expire(key, timeout):
        cache = query_cache()
        return cache.expire(key, timeout)

    """删除某个key 所有redis类型适用"""
    @staticmethod
    def delete(key):
        cache = query_cache()
        return cache.delete(key)
    
    """其它类型后面在补充 都挺简单的 redis有什么命令 这里就有什么方法"""

4.拦截器redis实现单点登录

单点登录:python采用多台服务器集群

思路:

1.第一次登录,前台输入用户名密码无论走到哪台服务器都拦截器放过
2.进入这台服务器,通过用户名密码查询数据库,查询失败返回登录失败,
成功后:A:生成一个cookie (token=随机不重复字符串)
B:redis存储一个键值对,(随机不重复字符串=用户信息的json字符串),并设置过期时间为30分钟

这样只要用户浏览器没变,那么cookie就在,cookie在token就在  根据token就可以拿到随机字符串,在访问后台无论走到集群的哪个服务器都能查询到redis的值,再拦截器进行拦截,就完成了单点登录

过期时间:每次访问后台都刷新下redis的过期时间即可
退出登录就根据token删除redis就可以了

代码:

views.py

import inspect
from django.forms import model_to_dict
from django.http import JsonResponse
from django.shortcuts import render
# Create your views here.
from django.views import View
from .models import Users
import json
from util.RedisUtil import RedisUtils


class user_view(View):
    # 登录接口
    def post(self, request):
        # 获得请求的json数据 包含username与password
        decode = request.body.decode("utf-8")
        loads = json.loads(decode)
        username = loads.get('username')
        password = loads.get('password')
        try:
            user = Users.objects.get(username=username, password=password)
        except Users.DoesNotExist:
            return JsonResponse({<!-- -->'code': 500, "msg": '用户名或密码错误'})
        # 生成cookie
        response = JsonResponse({<!-- -->'code': 200, 'msg': '登录成功'})
        # 这里先不封装 做项目再封装  value就随便写个abcde  开发的时候 需要利用工具类生成随机字符串
        # 过期时间不设置 默认浏览器关闭就没有了 如果是有记住我什么功能 再设置时间  httponly 防止攻击
        response.set_cookie(key='token', value='abcde', httponly=True)
        # 把user对象转换为json字符串
        to_dict = model_to_dict(user)
        dumps = json.dumps(to_dict)
        # redis放入值  abcde是上面的随机字符串 一定要对应
        # 存储用户的时候加上固定前缀  后面项目有补充功能 比如给在线用户xxxx 有固定前缀就可以很快找到所有在线用户 这些都是经验
        RedisUtils.set("login_" + 'abcde', dumps, 60 * 30)
        return response

interceptors.py 注意参考前面的拦截器

from django.http import JsonResponse
from django.utils.deprecation import MiddlewareMixin
from django_redis import get_redis_connection
from util.RedisUtil import RedisUtils


class a(MiddlewareMixin):
    def process_request(self, request):
        # 判断路径是否是登录或者注册 是就直接放过
        path_info = request.path_info
        if path_info.lower() not in ['/login', 'register']:
            # 获得cookie 的token
            token_value = request.COOKIES.get('token')
            if token_value:
                # 根据token对应的字符串token_value 去获取redis
                # 加上固定前缀
                redis_value = RedisUtils.get('login_' + token_value)
                if redis_value:
                    # 说明用户是登录状态 并且没有过期,那么就改一下过期时间
                    RedisUtils.ttl('login_' + token_value, 30 * 60)
                else:  # cookie有 但是redis没有 那么就是用户长时间未操作页面 登录超时
                    return JsonResponse({<!-- -->"code": 500, "msg": '登录超时'})

            else:
                return JsonResponse({<!-- -->"code": 500, "msg": '请先登录'})

    def process_response(self, request, response):
        print('A response')
        return response


# 这个b没撒用 拦截器的时候加的 难得删除了
class b(MiddlewareMixin):
    def process_request(self, request):
        print("b request")

    def process_response(self, request, response):
        print('b response')
        return response

urls.py

from django.urls import path, re_path, include
# 导入user_view
from .views import user_view

urlpatterns = [
    # <username> 等于 <str:username> 表示传递字符串   在view层用username获取
    path('login/', user_view.as_view(), name='getUserByUsername'),
]

测试即可(测试的时候记得关闭csrf,setting里面先注释)

tips:jwt做登录对吗?采用jwt去登录的个人认为不对,

jwt是适合做比如你注册了 在15分钟内进入邮箱验证 的时候 携带的凭证 ,在去激活的时候进行验证用

因为jwt的过期时间一变 jwt就会变,如果做登录,你得发多少个jwt? jwt发得越多 被泄露就越高.

很多朋友又会说jwt有加密,那我token不能加密吗?

拦截不都是一样的么?

那么如果提高登录的安全性呢?请看配套视频

5.django自带认证系统

Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统–auth,它默认使用 auth_user 表来存储用户数据。

from django.contrib import auth
方法名备注
create_user创建用户
authenticate登录验证
login记录登录状态
logout退出用户登录
is_authenticated判断用户是否登录
login_required装饰器进行登录判断

先有个了解,我们在后续项目djangorestframework实战中去做
下周补充
上一篇django入门(三)

免费分享,平时搬砖,周末会录制匹配的视频。配套视频地址:https://wwwbilibilicom/video/BV1eQ4y1U7os/当你想要放弃的时候,想想当初为什么坚持到了现在!!!新建项目
python三大主流web框架Django:特点:大而全自带的功能特别多不足:有时候过于笨重flask特点:小而精自带的功能特别少,第三方模块特别多不足:比较依赖于第三方的开发者tornado特点:异
Form表单AdminDjangoForm表单django中的form一般有两种功能:输入html验证用户输入1,先写一个formimportrefromdjangoimportformsfromdj
为什么提交高质量的bug因为这是测试师的职责所在,测试师存在的意义。2bug的定义软件未实现产品说明书要求的功能产品出现了产品说明书指明不应该出现的错误软件实现了产品说明书未提到的功能(画蛇添足
本人java10年开发经验,现就职于电信,因工作需要学习python,记录自己的学习记录。后面也会持续分享真实工作经验,及项目后面做过项目后,对python有更深的理解了,会录制免费视频,讲解真实项目
0ORM操作1、必会的13条返回对象列表的allfilterexcludeorder_byreversedistinct特殊的对象列表valuesvalues_list返回对象的getfirstlas
这节我们实现修改数据的功能,惯例,还是先上代码:urlspyurlpatterns[path('curd/edit/',viewscurd_edit,name'curdedit'),path('cur
Django框架(部署nginx与对接acapp来源:https://wwwacwingcom/activity/content/code/content/2037153/y总教程:https:
1Admin:admin是django自带的功能强大的自动化数据管理界面被授权的用户可以直接在Admin中管理数据库(增、删、改、查Django提供了许多针对Admin的定制功能2配置Admin
下载djangogitclonehttps://githubcom/django/djangogit安装pythonsetuppyinstall创建项目mysnsdjangoadminpystartp