web框架:Django进阶(一)

django进阶

  • 模板
  • 中间件
  • ORM操作(pymysql + SQL语句) 内部会转化为sql语句,所以性能会减低,开发效率高
  • session和cookie
  • 缓存(很多种方式)

内容回顾

  • 请求周期

    • 路由系统

      • 最基本路由关系
      • 动态路由(含正则)
      • 路由分发不同的app中 + include + 本质 + name + namespace
    • 视图

      • 类和函数(FBV和CBV)

      • 参数 request

        • 请求数据
        • 自定义数据
      • 响应

        HttpResponse/JsonResponse/render/redirect
        return HttpResponse("...")
        
        响应头
        obj = HttpResponse("...")
        obj['xxxxx'] = "值"
        return obj
        
  • 其他知识

    • 虚拟环境

    • 纯净版项目,内置app功能去掉。

    • 多app,嵌套到apps目录。

    • pycharm创建django项目 + 虚拟环境

      • 最新的django项目
      • 低版本(环境+项目+django文件模板)
    • settings配置

      django默认settings [先加载] 500
      项目目录settings    [后加载] 20
      
    • 静态资源

      • 静态文件,项目必备【项目根目录,每个app目录下static - app注册顺序】
      • 媒体文件,用户上传

1.模板

1.1 寻找html模板顺序

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                # 'django.contrib.auth.context_processors.auth',
                # 'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

优先去项目根目录 > 每个已注册的app的templates目录找。

如何选择:

  • 简单的项目,模板都放在根目录。
  • 复杂的项目,模板放在各自的app中,公共部分放在templates目录。

将模板放到各自app中,更有利于组件化

如果不要求组件化,完全可以在根目录的templates分类存放

修改内置app的模板也是同样的套路:

如果想修改django内置app的模板,可以在templates下创建内置app名称的文件夹。

1.2 模板处理的本质

一定是django在将html渲染完成之后(占位符替换后),才将完整的文本信息返回给浏览器的

渲染完成后,生成了字符串,再返回给浏览器

在这里插入图片描述

如果将js代码单独放入文件,就不会替换了。

如果通过导入js文件的形式:浏览器在发现js语句后会再向服务端发送一个请求来单独获取js文件,而此时js文件在static文件夹下,就直接通过static系统直接发送给浏览器了,不需要经过路由系统了。所以此时js文件中的字符串没有被渲染。

以下是浏览器处理 JavaScript 文件的一般流程:

  1. HTML解析

    • 浏览器首先解析 HTML 文档,当遇到 <script> 标签时,会根据标签中的 src 属性确定 JavaScript 文件的位置。
  2. 发送请求获取JS文件

    • 如果 <script> 标签包含 src 属性,浏览器会向该 URL 发送一个 HTTP 请求,请求获取 JavaScript 文件。这个 URL 可以是相对路径或绝对路径。
  3. 静态文件服务

    • 如果 JavaScript 文件位于 Django 的 STATIC_URL 指定的静态文件目录中,Django 的静态文件服务会处理这个请求。这意味着浏览器会直接从静态文件目录获取 JavaScript 文件,而不需要经过 Django 的视图系统。
  4. 渲染JavaScript代码

    • 浏览器接收到 JavaScript 文件后,会执行其中的代码。如果 JavaScript 文件中包含字符串需要渲染,这些字符串需要在发送请求之前就处理好。
  5. 模板渲染

    • 如果 JavaScript 文件中的字符串需要动态渲染(例如,包含变量或模板标签),这些字符串必须在服务器端的模板渲染过程中处理。这意味着 JavaScript 文件应该作为模板的一部分,通过 Django 的模板系统进行渲染。
  6. 模板标签

    • 在 Django 模板中,可以通过 {% static %} 模板标签引入静态文件的 URL。这样可以确保 URL 是正确的,并且可以处理模板中的变量。
  7. 缓存处理

    • 浏览器和服务器可能会对静态文件进行缓存处理,减少重复的请求和提高加载速度。

总结来说,你的理解是正确的:当 JavaScript 文件通过 <script src="..."> 标签引入时,浏览器会直接从静态文件服务获取文件,而不是通过 Django 的视图系统。因此,文件中的字符串不会通过 Django 的模板系统进行渲染。如果需要动态渲染这些字符串,需要在服务器端的模板渲染过程中处理。

在这里插入图片描述

1.3 常用语法

在这里插入图片描述

1.4 内置函数

在django模板语法中提供了内置函数让我们来。

在这里插入图片描述

1.5 自定义模板功能

自定义模板函数:

  1. 创建templatetags文件夹,并创建一个py文件,并自定义模板函数

    1. filter

      多适用于数据处理,1到2个参数,if判断

      定义:@register.filter

      使用:通过==管道符|==使用:{{ ‘string’|myfunc }}

    2. simple_tag

      多适用于文本展示,参数无限制 & 返回文本信息

      定义:@register.simple_tag

      使用:通过类似加载static的url的方式{% mytag 'arg1' 'arg2' 'arg3' %}

    3. inclusion_tag

      多适用于html片段展示,参数无限制 & 返回html片段

      定义:@register.inclusion_tag(“app01/xxxx.html”)

      返回的是已经渲染完成的html片段

      使用:通过类似加载static的url的方式{% mytag 'arg1' 'arg2' 'arg3' %}

  2. 在模板文件中{% load xx %}导入文件

  3. 使用函数

在这里插入图片描述

三种方式:

  • filter

    - 数据处理,参数:1~2个
    - 数据处理,if条件
    
  • simple_tag

    参数无限制 & 返回文本
    
  • inclusion_tag

    参数无限制 & HTML片段
    

需求来了:根据用户权限不同显示不同的菜单。(inclusion_tag)

在这里插入图片描述

1.6 继承和母版

  1. 如果有extends继承的话,先加载母版,将block替换掉,得到整体的原始文本
  2. 第二步再进行渲染(替换字符串),所以母版中的占位符字符串也会被替换

母版中至少要包含:

  • html:{% block body %}{% endblock %}
  • css:{% block css %}{% endblock %}
  • js:{% block js %}{% endblock %}

在这里插入图片描述

在这里插入图片描述

1.7 模板的导入

可以通过include进行片段替换:{% include “app01/index.html” %}

  1. 如果有extends继承的话,先加载母版,将block替换掉,得到整体的原始文本
  2. 再找include,将未渲染的片段替换
  3. 进行渲染(替换字符串),所以母版中的占位符字符串也会被替换

在这里插入图片描述






2.django中间件

在这里插入图片描述

  • 定义方法
  • 注册

2.1 原始方式

在这里插入图片描述

在这里插入图片描述

2.2 MiddlewareMixin(建议)

源码实现

基于反射实现出来可以直接通过继承MiddlewareMixin类来定义中间件,

只需简单的定义process_request函数process_response函数,而无需再定义__call__方法。

  1. 第一个hasattr是对应请求中间件的,如果定义了process_request,
    就在view视图函数执行之前先执行process_request,process_request可以没有或者没有返回值,一般没有

    • 如果response为空(process_request没有返回值),response就是view函数的返回值;

    • 如果response为不为空(process_request有返回值),response就是process_request函数的返回值;

      此时,在执行response=response or self.get_response(request)时,就不会执行后面的函数了,

      包括之后注册的中间件函数,view视图函数,而是直接去执行该process_request对应的process_response函数,以及已经执行过process_request的中间件对应的process_response函数

      在这里插入图片描述

  1. 第二个hasattr是对应响应中间件的,如果定义了process_response,
    就在view视图函数执行之后先执行process_response。

    process_response一定要有返回值。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

注意:django1版本。

源码:

  • 面向对象

    class MyMd(object):
        def __init__(self....):
            pass
        
        def __call__(self,....):
            pass
            
    django内部默认执行call方法,传入参数。
    
  • 反射

    class MyMd(object):
        def __init__(self....):
            pass
        
        def __call__(self,....):
            if hasattr(self,'process_request'):
                response = self.process_request(request)
    		...
         
    django内部默认执行call方法,传入参数。
    
    class MiddlewareMixin:
        def __init__(self, get_response=None):
            self.get_response = get_response
            
        def __call__(self, request):
            response = None
            if hasattr(self, 'process_request'):
                response = self.process_request(request)
            response = response or self.get_response(request)
            if hasattr(self, 'process_response'):
                response = self.process_response(request, response)
            return response
        
        
    class MyMd(MiddlewareMixin):
        
        def process_request(self,request):
            ...
        
        def process_response(self,request, response):
            ...
        
    django内部默认执行call方法,传入参数。
    

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.3 prcess_request的执行时,是否已执行了路由匹配?

没有

  1. 中间件中的request.reslover_match对象为空
  2. 视图函数中的request.reslover_match对象为路由匹配信息

在这里插入图片描述

request.resolver_match

2.4 process_view

注意:process_view是在django中源码中写死了。

路由匹配成功后,还要再轮流执行中间件中的process_view函数

如果process_view中有返回值,会跳过view视图函数,从最后一个中间件的process_response函数轮流执行。

在这里插入图片描述

process_request和process_view
  • 为什么有了process_request还要有process_view呢?

    process_request和process_view的区别是:一个没有匹配路由,一个已经匹配路由

    process_request(没有匹配路由):可以用做一些所有路由都要做的流程

    process_view(已经匹配路由):可以做一些特定的路由要做的流程

2.5 其他

  • process_exception

    视图函数异常,process_exception会捕获异常,也可以返回响应

    在这里插入图片描述

    在这里插入图片描述

  • process_template_response(了解即可)

    只有在视图函数返回TemplateResponse对象时,才会触发中间件中的process_template_response方法,该方法内部时间上会调用render()方法。

    所以说process_template_response这种方法实际上就是:

    将视图函数直接返回render()分为了两步

    1. 返回TemplateResponse对象
    2. process_template_response函数中调用render()方法

    在这里插入图片描述

    在这里插入图片描述

python面向对象中__call__方法

小结

  • 定义中间类

  • 类方法

    • process_request
    • process_view
    • process_reponse
    • process_exception,视图函数出现异常,自定义异常页面。
    • process_template_response,视图函数返回TemplateResponse对象 or 对象中含有.render方法。
  • 应用场景:统一用户验证,解决跨越请求

    在这里插入图片描述

3.ORM操作

orm,关系对象映射,本质翻译的。

在这里插入图片描述

3.1 表结构

实现:创建表、修改表、删除表。

在app中的models.py中按照规则编写类 ===> 表结构。

  • 编写类

    from django.db import models
    
    
    class UserInfo(models.Model):
        name = models.CharField(max_length=16)
        age = models.IntegerField()
    
  • 注册app

    INSTALLED_APPS = [
        # 'django.contrib.admin',
        # 'django.contrib.auth',
        # 'django.contrib.contenttypes',
        # 'django.contrib.sessions',
        # 'django.contrib.messages',
        'django.contrib.staticfiles',
        'apps.app01.apps.App01Config',
        'apps.app02.apps.App02Config',
    ]
    
  • 命令,django根据models中类生成一个 对数据库操作的配置文件 => migrations

    python manage.py makemigrations
    

    在这里插入图片描述

  • 命令,读取已经注册么给app中的migrations目录将配置文件 -> 转换成:生成表,修改表 SQL -> 连接数据库去运行。

    python manage.py migrate
    
    • 那个数据库?
    • 数据库账户和密码?
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
    

    在这里插入图片描述

常见问题:请不要再手动去修改数据的表结构 + 时刻保证 ORM和数据表是对应。

3.1.1 常见字段和参数
  • 字段

    CharField
    
    SmallIntegerField
    IntegerField
    positiveIntegerField(无符号)
    BigIntegerField
    
    DateField
    DateTimeField
    
    BooleanField  -> 其实数据库不支持真假,根据SmallIntegerField创造出来出来。 0  1
    
    DecimalField  -> 精确的小数
    
  • 参数

    name = models.CharField(verbose_name="姓名", max_length=16)
    name = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈")
    
    # 经常查询,速度快(MySQL,https://www.bilibili.com/video/BV15R4y1b7y9)
    name = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈", null=True, blank=True, db_index=True)
    email = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈", null=True, blank=True, unique=True)
    
    # 在数据库存储时只能是:sh、bj (上海、北京一般用于页面显示中文)
    code = models.CharField(verbose_name="姓名", max_length=16, choices=(("sh", "上海"), ("bj", "北京")),default="sh")
    
    # 不用 max_length=16
    count = models.IntegerField(verbose_name="数量", default=1, null=True, blank=True, unique=True)
    code = models.IntegerField(verbose_name="性别",choices=((1, "男"), (2, "女")),default=1)
    
    register_date = models.DateField(verbose_name="注册时间", auto_now=True)
    
    amount = models.DecimalField(verbose_name="余额", max_digits=10, decimal_places=2)
    

示例:

from django.db import models


class UserInfo(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=16, db_index=True)
    age = models.PositiveIntegerField(verbose_name="年龄")
    email = models.CharField(verbose_name="邮箱", max_length=128, unique=True)
    amount = models.DecimalField(verbose_name="余额", max_digits=10, decimal_places=2, default=0)
    register_date = models.DateField(verbose_name="注册时间", auto_now=True)


class Goods(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)
    # detail = models.CharField(verbose_name="详细信息", max_length=255)
    detail = models.TextField(verbose_name="详细信息")
    price = models.PositiveIntegerField(verbose_name="价格")
    count = models.PositiveBigIntegerField(verbose_name="库存", default=0)
3.1.2 表关系

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

注意:ManyToManyField生成的表字段只能id/bid/gid


若有错误与不足请指出,关注DPT一起进步吧!!!

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我DPT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值