Django框架

文章目录

  • Django流程
    • 创建Django项目
    • 创建子应用
    • 视图View.py
    • URL
    • 模板Template
    • 综合案例总结
    • Debug
    • 静态文件
    • apps配置相关
  • 二、模型(models.py)
    • 外键
    • 修改数据库(更换为MySQL)
    • iPython(python manage.py shell)
    • F和Q对象(属性与属性之间的比较,多条件查询)
    • 聚合函数(计算,累计)
    • 排序
    • 关联查询(多个表)
    • 关联查询的筛选
    • 查询集
    • 分页
  • 三、视图
    • 项目准备工作
    • 允许IP访问
    • 配置URLconf
    • reverse路由跳转(利用参数name方便修改URL)
    • postman工具下载
    • HttpRequest对象(通过位置获取url参数)
      • 关键字参数(url路径)
      • GET方式传递查询字符串
      • POST表单数据
      • POST json数据
      • 请求头
      • 其他常用HttpRequest对象属性
    • HttpResponse对象
      • HttpResponse
      • JsonResponse
      • 重定向(页面跳转)
      • 状态保存
      • Cookie
    • Session
    • 类视图
    • 中间件
  • 模板
      • 基本配置
      • 使用模板
    • 模板语法
    • 模板继承
    • Django使用jinja2模板
    • CSRF(跨站请求伪造)
  • session保存至redis中
    • CSRF的django使用

django文档: https://docs.djangoproject.com/en/4.2/
下面内容基本上可以在该链接中搜索

Django流程

Django是用python语言写的开源web开发框架,并遵循MVC设计。Django的主要目的是简便、快速的开发数据库驱动的网站·它强调代码复用,多个组件可以很方便的以”插件”形式服务于整个框架,Django有许多功能强大的第三方插件,你甚至可以很方便的开发出自己的工具包·这使得Django具有很强的可扩展性。它还强调快速开发和DRY(DoNot Repeat YourselD)原则。
重量级框架:对比Flask框架,Django原生提供了众多的功能组件,让开发更简便快速。提供项目工程管理的自动化脚本工具数据库ORM支持( 对象关系映射),模板,表单,Admin管理站点,文件管理,认证权限,session机制,缓存
MVT格式(Model View Template):有一种程序设计模式叫MVC(Model View Controller),其核心思想是分工、解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容。
Django框架_第1张图片

Django框架_第2张图片

环境配置:

安装django:pip install django

在一台电脑上想开发多个不同的项目,需要用到用一个包的不同版本,如果用pip install django安装,会将最新的覆盖之前的版本,解决该问题的方式是使用虚拟环境
虚拟环境:可以搭建独立的 python运行环境,使得单个项目的运行环境与其它项目互不影响

安装虚拟环境(Linux):pip install virtualenvpip install virtualenvwrapper
创建虚拟环境:mkvirtualenv [-p python3] 虚拟环境名 (加-p指定使用python3,不指定默认使用python2)如:mkvirtualenv py_django
创建会进入虚拟环境,进入虚拟环境后执行指令workon可以查看当前有哪些虚拟环境
切换虚拟环境:workon 虚拟环境名
删除虚拟环境(不能删除正在使用的虚拟环境):rmvirtualenv 虚拟环境名
退出虚拟环境:deactivate
在虚拟环境中可以使用pip安装库:pip install 库名

创建Django项目

创建Django项目django-admin startproject name
Django框架_第3张图片

运行指令后多了如下文件,manage.py是一个管理工具/脚本(如创建子应用时会用到),settings.py设置相关,urls.py路由相关,wsgi.py程序入口
Django框架_第4张图片

运行项目python manage.py runserver [127.0.0.1:8001](中括号内可指定)
刚开始运行没反应,在file>settings中进行如下设置,然后重启pycharm运行指令即可
Django框架_第5张图片

Django框架_第6张图片

Django框架_第7张图片

创建子应用

创建子应用python manager.py startapp name
运行指令后多了如下几个文件
view.py视图相关,tests.py测试相关,models.py模型相关,migrations迁移相关,admin.py后台相关,apps.py当前子应用相关
在这里插入图片描述

Django框架_第8张图片

然后在主应用中将该其与子应用关联起来,有两种方式(子应用名或者子应用名.apps.子应用名Config
Django框架_第9张图片

模型的迁移:Model用于和关系型数据库交互
模型:当前项目的开发,都是数据驱动的;以下为书籍信息管理的数据关系: 书籍和人物是 :一对多关系;要先分析出项目中所需要的数据,然后设计数据库表
Django框架_第10张图片

书籍信息表

字段名 字段类型 字段说明
id AutoField 主键
name CharField 书名
id name
1 西游记
2 三国演义

人物信息表

字段名 字段类型 字段说明
id AutoField 主键
name CharField 人名
gender BooleanField 性别
book ForeignKey 外键
id name gender book
1 孙情空 False 1
2 白骨精 True 1
3 曹操 False 2
4 貂蝉 True 2

使用Django进行数据库开发的提示

MVT 设计模式中的 Model,专门负责和数据库交互。对应 (models.py)
由于 Model 中内了 ORM框架,所以不需要直接面向数据库编程
而是定义模型类,通过 模型类和对象 完成数据库表的 增制改查
ORM框架(如下图) 就是把数据库表的行与相应的对象建立联。互相转换,使得数据库的操作面向对象
Django框架_第11张图片

使用Django进行数据库开发的步骤 :

1.定义模型类
2.模型迁移
3.操作数据库

表与表之间关联的时候,必须要写on_delete参数,否则会报异常models.ForeignKey(BookInfo, on_delete=models.CASCADE)

on_delete=None, # 删除关联表中的数据时,当前表与其关联的field的行为
on_delete=models.CASCADE, # 删除关联数据,与之关联也删除
on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做
on_delete=models.PROTECT, # 删除关联数据,引发错误ProtectedError
# models.ForeignKey(‘关联表’, on_delete=models.SET_NULL, blank=True, null=True)
on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)
# models.ForeignKey(‘关联表’, on_delete=models.SET_DEFAULT, default=‘默认值’)
on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
on_delete=models.SET, # 删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

编写子应用login中的models.py,内容如下
Django框架_第12张图片

from django.db import models

# Create your models here.
'''
1.定义模型类
2.模型迁移
    2.1 先生成迁移文件(不会在数据库中生成表,只会创建一个数据表和模型的对应关系)
        python manage.py makemigrations
    2.2 再迁移(会在数据库中生成表)
        python manage.py migrate
3.操作数据库

在哪里定义模型
模型继承自谁就可以
ORM对应的关系
    表-->类
    字段-->属性
'''
class BookInfo(models.Model):
    '''
    1.主键 当前会自动生成
    2.属性复制过来就可以
    '''
    name = models.CharField(max_length=10)

class PeopleInfo(models.Model):
    name = models.CharField(max_length=10)
    # 性别
    gender = models.BooleanField()
    # 外键
    book = models.ForeignKey(BookInfo, on_delete=models.CASCADE)

编写之后,在pycharm下面的terminal中运行python manage.py makemigrations
Django框架_第13张图片

如果上面运行失败,是因为没有注册子应用(关联子应用),需要在主应用的settings.py中加上如下内容
Django框架_第14张图片
python manage.py makemigrations运行成功后,会在迁移文件中(子应用)生成如下文件
Django框架_第15张图片

内容如下

# Generated by Django 4.2 on 2023-04-22 14:16

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='BookInfo',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=10)),
            ],
        ),
        migrations.CreateModel(
            name='PeopleInfo',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=10)),
                ('gender', models.BooleanField()),
                ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='login.bookinfo')),
            ],
        ),
    ]

然后再terminal中继续执行python manage.py migrate,结果如下即表示迁移成功
Django框架_第16张图片

在主应用的settings.py中可以查看使用的是什么数据库
Django框架_第17张图片
由上面可以知道这个文件为保存的数据库
Django框架_第18张图片

打开该数据库,显示没有内容时,需要按如下步骤下载对应数据库的驱动

Django框架_第19张图片
Django框架_第20张图片

下载之后,上面的指令执行完,该数据库里面会多两个表格(login_bookinfo,login_peopleinfo)
Django框架_第21张图片

上面创建的项目中,自带了登入界面,即,运行python manage.py runserver之后,浏览页面http://127.0.0.1:8000/admin会自动跳到登入页面,页面如下
Django框架_第22张图片

接着我们将上面的英文修改为中文,settings.py中将LANGUAGE_CODE = 'en-us'改为LANGUAGE_CODE = 'zh-Hans',然后刷新页面,显示的内容就是中文格式

# LANGUAGE_CODE = 'en-us'
# 语言
LANGUAGE_CODE = 'zh-Hans'

Django框架_第23张图片

还可以修改时区,将TIME_ZONE = 'UTC'修改为TIME_ZONE = 'Asia/Shanghai',这里看不出效果

# LANGUAGE_CODE = 'en-us'
# 语言
LANGUAGE_CODE = 'zh-Hans'

# TIME_ZONE = 'UTC'
# 时区
TIME_ZONE = 'Asia/Shanghai'

接着查看auto_user数据库没有数据
Django框架_第24张图片
接着使用指令创建一个后台管理员用户:python manage.py createsuperuser,运行指令后输入用户名(admin),邮箱([email protected]),密码(abc123456),执行指令后,查看auto_user数据库中有一条数据

Django框架_第25张图片
创建之后,从新运行项目,然后浏览http://127.0.0.1:8000/admin页面,输入账户(admin)和密码(abc123456)可以登入
Django框架_第26张图片

Django框架_第27张图片

在子应用的admin.py中输入如下内容,然后刷新页面可以看到多了如下内容

from django.contrib import admin
from login.models import BookInfo

# Register your models here.
# 注册模型
# admin.site.register(模型类)
admin.site.register(BookInfo)

Django框架_第28张图片
点击进去就可操作添加数据
在这里插入图片描述
Django框架_第29张图片

保存了两条数据,就有两条数据内容,数据库中也可以查看的到
在这里插入图片描述
这是不知道哪个是西游记,哪个是三国演义,需要在子应用的models.py中添加个def __str__(self):函数返回self.name,然后浏览页面就会显示该内容

from django.db import models

# Create your models here.

class BookInfo(models.Model):
    '''
    1.主键 当前会自动生成
    2.属性复制过来就可以
    '''
    name = models.CharField(max_length=10)

    def __str__(self):
        return self.name

class PeopleInfo(models.Model):
    name = models.CharField(max_length=10)
    # 性别
    gender = models.BooleanField()
    # 外键
    book = models.ForeignKey(BookInfo, on_delete=models.CASCADE)

Django框架_第30张图片

视图View.py

用户在URL中请求的是视图,视图接收请求后进行处理,并将处理的结果返回给请求者
使用视图时需要进行两步操作:定义视图;配置URLconf

定义视图
视图就是一个 Python 函数,被定义在 应用的 views.py 中
视图的第一个参数是 HttpRequest 类型的对象 reqeust,包含了所有 请求信息
视图必须返回 HttpResponse对象,包含返回给请求者的 响应信息
需要导入 HttpResponse 模块: from django.http import HttpResponse
定义视图函数:响应字符串 OK! 给客户端

子应用的view.py内容如下

from django.shortcuts import render
from django.http import HttpRequest

# Create your views here.
'''
视图
就是python函数
函数的第一个参数就是请求,和请求相关的,是HttpRequest对象
必须要返回一个相应,相应是HttpResponse的实例对象/子类实例对象
'''
def index(request):
    return HttpRequest('index')

URL

在上面的基础上,我们没有定义URL,访问http://127.0.0.1:8000/index得到的是这样的页面
Django框架_第31张图片
做如下配置可以正常浏览
在主应用中的settings.py中的如下内容是url的配置,如果有个文件abc.py是URL的文档,可以改为ROOT_URLCONF = ‘abc.py’

# ”ROOT_URICONE 是我们工程的URL的配置的入口
# 默认是 工程名.urls
# 可以修改,默认不改
ROOT_URLCONF = 'book.urls'

在主应用的urls.py中内容添加一项path('', include('login.urls'))

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


'''
1.urlpatterns是固定写法,它的值是列表
2.浏览器中输入的路径会和urlpatterns中的每一项匹配
    如果匹配成功则直接引导到相应的模块,不成功则直接返回404.
3.urlpatterns中的元素是url,url的第一个参数是正则
4.浏览器的路由http://ip:port/path/?key=value中,http://ip:port/和get post不参数正则匹配
5.如果和当前的某项匹配成功,则引导到子应用中继续匹配
    如果匹配成功,则停止匹配返回响应的视图

'''
# 路由匹配
urlpatterns = [
    # 参照:正则;函数或者include函数
    path('admin/', admin.site.urls),
    # 添加一项,上面没匹配,跳转到子应用的urls.py中匹配
    # include导入其他路由文件中
    path('', include('login.urls'))
]

在子应用中创建urls.py,内容如下

from django.urls import path
from login.views import index

# 路由匹配
urlpatterns = [
    # 参照:正则;函数
    path('index/', index),
]

子应用的views.py内容如下

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
'''
视图
就是python函数
函数的第一个参数就是请求,和请求相关的,是HttpRequest对象
必须要返回一个相应,相应是HttpResponse的实例对象/子类实例对象
'''
def index(request):
    return HttpResponse('index')

经过上面修改,继续浏览http://127.0.0.1:8000/index/可以得到如下页面
Django框架_第32张图片

urls路由匹配
Django框架_第33张图片

Django框架_第34张图片

模板Template

在项目上创建template目录,在该目录中创建一个index.html文件
Django框架_第35张图片

index.html文件内容如下

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Django模板title>
head>
<body>
    <a>Django模板a>
body>
html>

在主应用的settings.py中做以下设置
Django框架_第36张图片
然后修改子应用的views.py文件内容,内容如下

from django.shortcuts import render
# from django.http import HttpResponse

# Create your views here.
'''
视图
就是python函数
函数的第一个参数就是请求,和请求相关的,是HttpRequest对象
必须要返回一个相应,相应是HttpResponse的实例对象/子类实例对象
'''
def index(request):
    # request,template name,context=None
    # 参数1: 当前的请求
    # 参数2: 模板文件
    return render(request, 'index.html')
    # return HttpResponse('index')

然后浏览http://127.0.0.1:8000/index/显示页面为index.html的内容,页面如下
Django框架_第37张图片

如果要将参数传入该index.html中,可以进行如下操作
修改templatge中的index.html文件,接收views.py传入的数据(这里的name是下面传入字典的键,得到的就是下面传入的字典的值Python
Django框架_第38张图片

子应用的views.py内容如下(return中添加context参数传入index.html

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
'''
视图
就是python函数
函数的第一个参数就是请求,和请求相关的,是HttpRequest对象
必须要返回一个相应,相应是HttpResponse的实例对象/子类实例对象
'''
def index(request):
    # request,template name,context=None
    # 参数1: 当前的请求
    # 参数2: 模板文件
    # 参数3:context传递参数
    context = {
        'name': 'Python'
    }
    # 将context传递给index.html
    return render(request, 'index.html', context=context)
    # return HttpResponse('index')

浏览页面如下
Django框架_第39张图片

综合案例总结

创建项目:django-admin startproject bookmanager
进入项目:cd bookmanager
添加子应用:python manage.py startapp book
在主项目的settings.py中配置
Django框架_第40张图片

在子应用的models.py中定义模型

from django.db import models

# Create your models here.
class BookInfo(models.Model):
    name = models.CharField(max_length=10)

运行会生成数据库python manage.py makemigrationspython manage.py migrate
在子应用的views.py中设置

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.=
def index(request):
    return HttpResponse('index')

在子应用中创建urls.py路由文件

from django.urls import path
from login.views import index


urlpatterns = [
    # 参照:正则;函数
    path('index/', index),
]

在主应用的urls.py中添加引入该路由

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

urlpatterns = [
    # 参照:正则;函数
    path('admin/', admin.site.urls),
    # 添加一项
    path('', include('login.urls'))
]

在项目上创建template目录,在该目录中创建一个index.html文件,内容如下
Django框架_第41张图片

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Django模板title>
head>
<body>
    <a>Django模板{{name}}a>
body>
html>

在主应用的settings.py中做以下设置(BASE_DIR在该文件上面有定义)
Django框架_第42张图片
然后修改子应用的views.py文件内容,内容如下(return中添加context参数传入index.html

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(request):
    # request,template name,context=None
    # 参数1: 当前的请求   参数2: 模板文件   参数3:context传递参数
    context = {
        'name': 'Python'
    }
    # 将context传递给index.html
    return render(request, 'index.html', context=context)
    # return HttpResponse('index')

浏览页面如下
Django框架_第43张图片

如果需要后台账户(admin):python manage.py createsuperuser,然后输入账号邮箱密码等信息
在子应用的admin.py中添加如下内容

from django.contrib import admin
from login.models import BookInfo

# Register your models here.
admin.site.register(BookInfo)

然后在127.0.0.1:8000/admin登入之后可以管理数据库,添加数据
为了能够显示数据,在子应用的models.py中做如下修改即可

from django.db import models

# Create your models here.
class BookInfo(models.Model):
    name = models.CharField(max_length=10)

    def __str__(self):
        return self.name

要将数据库中的数据写入到index.html中,需要做如下修改
template中index.html内容如下(遍历读取数据

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Django模板title>
head>
<body>
    <ul>
		
        {% for book in books %}
            <li>{{ book }}li>
        {% endfor %}
    ul>
body>
html>

修改views.py,获取数据库数据,传入index.html中

from django.shortcuts import render
from login.models import BookInfo

def index(request):
    books = BookInfo.objects.all()
    context = {
        'books':books
    }
    # 将context传递给index.html
    return render(request, 'index.html', context=context)

Debug

当浏览URL错误的时候,会显示如下页面
Django框架_第44张图片
是因为主应用的settings.py里面有这行代码,如果改成False就不会显示

# 开发者进行调试使用,当部署上线的时候需要改为False
# 为True时,浏览页面发生错误,会告诉你那里错了
DEBUG = True

静态文件

静态文件:项目中的CSS、图片、js都是静态文件。一般会将静态文件放到一个单独的目录中,以方便管理。在html页面中调用时,也需要指定静态文件的路径,Diango中提供了一种解析的方式配置静态文件路径,静态文件可以放在项目根目录下,也可以放在应用的目录下,由于有些静态文件在项目中是通用的,所以推荐放在项目的根目录下,方便管理。
为了提供静态文件,否要配置两个参数 :

STATICFILES_DIRS:存放查找静态文件的目录
STATIC_URL:访问静态文件的URL前缀

在项目中创建static文件夹,在文件夹中保存图片
Django框架_第45张图片

在主应用的settings.py中进行如下配置

# Django通过STATIC_UR区分静态资源和动态资源
STATIC_URL = 'static/'
# 告诉系统静态文件在哪,BASE_DIR变量在该文件上面有定义
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

然后访问http://127.0.0.1:8000/static/1.jpeg就会出现static中的图片
Django框架_第46张图片

apps配置相关

在子应用的apps.py中添加这一行
Django框架_第47张图片

然后在主应用settings.py中一定要用这种格式
Django框架_第48张图片

运行显示如下
Django框架_第49张图片

二、模型(models.py)

1.定义模型类
2.模型迁移
2.1 先生成迁移文件(不会在数据库中生成表,只会创建一个数据表和模型的对应关系)
python manage.py makemigrations
2.2 再迁移(会在数据库中生成表)
python manage.py migrate
3.操作数据库
1、ORM对应的关系
表–>类
字段–>属性
2.模型类需要继承自models.Model
3.模型类会自动为我们添加一个主键
4.属性名=属性类型(选项)charfield类型必须设置max_length

属性类型

类型 说明
AutoField 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性
BooleanField 布尔字段,值为True或False
NullBooleanField 支持Null·True、False三种值
CharField 字符串,参数max_length表示最大字符个数,charfield类型必须设置max_length
TextField 大文本字段,一般超过4000个字符时使用
lntegerField 整数
DecimalField 十进制浮点数,参数max_digits表示总位数,参数decimal_places表示小数位数
FloatField 浮点数
DateField 日期,参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于”最后一次修改”的时间截,它总是使用当前日期,默认为False; 参数auto now add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False: 参数auto now add和auto now是相互排斥的,组合将会发生错误
TimeField 时间,参数同DateField
DateTimeField 日期时间,参数同DateField
FileField 上传文件字段
lmageField 继承于FileField,对上传的内容进行校验,确保是有效的图片

选项

选项 说明
null 是否为空
unique 唯一
default 设置默认值
varbose_name 主要是admin后台显示名字
from django.db import models

# Create your models here.
class BookInfo(models.Model):
    name = models.CharField(max_length=10, unique=True, verbose_name='名字')  # 唯一
    # 发布日期
    pub_data = models.DateField(null=True)
    # 阅读量
    readcount = models.IntegerField(default=0)
    # 评论量
    commentcount = models.IntegerField(default=0)
    # 是否逻辑删除
    is_delete = models.BooleanField(default=False)

    # def __str__(self):
    #     return self.name

在models.py里面可以修改表名

from django.db import models


class BookInfo(models.Model):
    
    name = models.CharField(max_length=10, unique=True, verbose_name='名字')

    class Meta:
        # 改表名
        db_table = 'bookinfo'
        # 修改后台admin的显示信息的配置
        verbose_name = 'admin'

    def __str__(self):
        return self.name

外键

models.py可以定义外键
数据库的外键级联操作

在设置外键时,需要通过on_delete选项指明主表除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量 :
CASCADE级联,删除主表数据时连通一起删除外键表中数据
PROTECT保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
SET_NULL设置为NULL,仅在该字段null=True允许为null时可用
SET_DEFAULT设置为默认值,仅在该字段设置了默认值时可用
SET()设置为特定值或者调用特定方法
DO_NOTHING不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常

from django.db import models

class BookInfo(models.Model):
    name = models.CharField(max_length=10, unique=True, verbose_name='名字')  # 唯一
    # 发布日期
    pub_data = models.DateField(null=True)
    # 阅读量
    readcount = models.IntegerField(default=0)
    # 评论量
    commentcount = models.IntegerField(default=0)
    # 是否逻辑删除
    is_delete = models.BooleanField(default=False)

    class Meta:
        # 改表名
        db_table = 'bookinfo'
        # 修改后台admin的显示信息的配置
        verbose_name = 'admin'

    def __str__(self):
        return self.name

class PeopleInfo(models.Model):
    # 有序字典
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    name = models.CharField(max_length=10,verbose_name='名称')
    # 性别
    gender = models.BooleanField(choices=GENDER_CHOICES, default=0)
    description = models.CharField(max_length=200, null=True)
    # 外键
    book = models.ForeignKey(BookInfo, on_delete=models.CASCADE)
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'peopleinfo'
        verbose_name = '人物信息'

    def __str__(self):
        return self.name

修改数据库(更换为MySQL)

在主应用的__init__.py中输入如下内容

import pymysql
pymysql.install_as_MySQLdb()

修改主应用的settings.py修改这段代码进行配置

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'book',
]

# 小型数据库:Sqlite
# 中型数据库:MySQL,Sqlserver
# 大型数据库:oracle,DB2
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1', # 主机
        'PORT': '3306',      # 端口
        'USER': 'root',      # 用户名
        'PASSWORD': 'mysql', # 密码
        'NAME': 'book',      # 指定数据库
    }
}

写入models.py内容

from django.db import models

class BookInfo(models.Model):
    name = models.CharField(max_length=10, unique=True, verbose_name='名字')  # 唯一
    # 发布日期
    pub_data = models.DateField(null=True)
    # 阅读量
    readcount = models.IntegerField(default=0)
    # 评论量
    commentcount = models.IntegerField(default=0)
    # 是否逻辑删除
    is_delete = models.BooleanField(default=False)

    class Meta:
        # 改表名
        db_table = 'bookinfo'
        # 修改后台admin的显示信息的配置
        verbose_name = 'admin'

    def __str__(self):
        return self.name

class PeopleInfo(models.Model):
    # 有序字典
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    name = models.CharField(max_length=10,verbose_name='名称')
    # 性别
    gender = models.BooleanField(choices=GENDER_CHOICES, default=0)
    description = models.CharField(max_length=200, null=True)
    # 外键
    book = models.ForeignKey(BookInfo, on_delete=models.CASCADE)
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'peopleinfo'
        verbose_name = '人物信息'

    def __str__(self):
        return self.name

然后运行python manage.py makemigrations
Django框架_第50张图片

现在数据库中还没有该数据库
Django框架_第51张图片

再执行python manage.py migrate
Django框架_第52张图片
执行之后,数据库中就有该数据
Django框架_第53张图片

cmd终端连接数据库之后插入数据

insert into bookinfo(name, pub_data, readcount, commentcount, is_delete) values
('射雕英雄传','1999-1-1','11','22',0),
('天龙八部','1999-11-11','22','33',0),
('笑傲江湖','1999-3-3','55','44',0);

insert into peopleinfo(name, gender, book_id, description, is_delete) values
('郭靖', 1, 1, '降龙十八掌',0),
('黄蓉', 0, 1, '打狗棍法',0),
('乔峰', 1, 2, '降龙十八掌',0),
('段誉', 1, 2, '六脉神剑',0),
('东方不败', 0, 3, '葵花宝典',0);

Django框架_第54张图片

在子应用的views.py中编写如下内容

from django.shortcuts import render
from django.http import HttpResponse
from book.models import BookInfo

# Create your views here.

def index(request):
    # 到数据库中查询数据
    books = BookInfo.objects.all()
    # 组织数据
    context ={
        'books': books
    }
    # 传递给模板
    # render(request, '', context)

    return HttpResponse('index')

iPython(python manage.py shell)

类似于 ipython的东西
python manage.py shell
执行之后在执行下面代码
from book.models import BookInfo
BookInfo.objects.all()
然后就会显示数据库中查询到的内容
Django框架_第55张图片

使用iPython新增数据

方式一

python manage.py shell

from book.models import BookInfo
book = BookInfo(
    name='python',
    pub_data='2000-01-01'
)
# 需手动调用save方法
book.save()
# 方式二:直接入库
# object模型的管理类
# 对模型的增删改查都找它
python manage.py shell

from book.models import BookInfo
BookInfo.objects.create(
    name='java',
    pub_data='2001-01-02'
)

修改更新数据

方式一

python manage.py shell

from book.models import BookInfo
# 先查询数据
# select * from bookinfo where id=1
book = BookInfo.objects.get(id=1)
# 再更新数据
book.readcount=20
# 调用save保存
book.save()

Django框架_第56张图片

方式二

python manage.py shell

from book.models import BookInfo
BookInfo.objects.filter(id=1).update(
    readcount = 100,
    commentcount = 200
)

Django框架_第57张图片

删除操作
方式一

python manage.py shell

from book.models import BookInfo
# 先获取数据
book = BookInfo.objects.get(id=5)
# 调用删除方法
book.delete()

方法二

python manage.py shell

from book.models import BookInfo

BookInfo.objects.filter(id=4).delete()

查询操作

get得到某一个数据
all获取所有的
count 个数

python manage.py shell

from book.models import BookInfo

# select * from bookinfo where id=1
book = BookInfo.objects.get(id=1)
book.name
book.readcount

# 不存在会抛出异常
try:
    book = BookInfo.objects.get(id=100)
except Exception:
    pass

# 获取所有数据
book = BookInfo.objects.all()

# count
BookInfo.objects.count()

filter,get,exclude查询

filter,get,exclude都是相当于where查询,select * from bookinfo where id=1
filter :筛选/过滤 返回 n个结果(n = 0/1/n)
get : 返回1个结果
exclude :排除掉符合条似剩下的结果,相当于not
语法新式,如filter(字段名__运算符=值)

python manage.py shell

from book.models import BookInfo

# 查询编号为1的图书
# exact精确的,准确的,就是等于
BookInfo.objects.get(id__exact=1)  # 返回单一对象
BookInfo.objects.get(id=1)  # 简写,同上
BookInfo.objects.filter(id__exact=1)   # 返回列表
BookInfo.objects.filter(id__exact=1)[0]
# 查询书名含'笑'的图书
BookInfo.objects.filter(name__contains='笑')
# 查询书名以‘部’结尾的图书
BookInfo.objects.filter(name__endswith='部')
# 查询书名为空的图书
BookInfo.objects.filter(name__isnull=True)
# 查询编号为1或3或5的图书
BookInfo.objects.filter(id__in=[1, 3, 5])
# 查询编号大于3的图书
# gt 大于   gte 大于等于
# lt 小于   lte  小于等于
BookInfo.objects.filter(id__gt=3)
# 查询数据id不为3的图书
BookInfo.objects.exclude(id=3)
BookInfo.objects.exclude(id__exact=3)
# 查询1980年发表的图书
BookInfo.objects.filter(pub_data__year='1980')
# 查询1990年1月1日后发表的图书
BookInfo.objects.filter(pub_data__gt='1990-1-1')

F和Q对象(属性与属性之间的比较,多条件查询)

F对象:用于属性与属性直接的比较,

F对象的语法形式
filter(字段名__运算符=F('字段名'))

如:查询阅读量大于等于评论星的图书。

python manage.py shell

from book.models import BookInfo
from django.db.models import F

# 查询阅读量大于等于评论量的图书
BookInfo.objects.filter(readcount__gt=F('commentcount'))
# 查询阅读量大于等于评论量两倍的图书
BookInfo.objects.filter(readcount__gt=F('commentcount')*2)

Q对象多条件查询,如:需要查询id大于2 并且阅读量大于20的书籍

Q对象语法形式
: Q()|Q()
并且:Q()&Q()
not:~Q()

python manage.py shell

from book.models import BookInfo
# 需要查询id大于2并且阅读量大于20的书籍
# 方式一
BookInfo.objects.filter(id__gt=2).filter(readcount__gt=20)
# 方式二
BookInfo.objects.filter(id__gt=2, readcount__gt=20)

# 方法三,使用Q对象
from django.db.models import Q
BookInfo.objects.filter(Q(id__gt=2)&Q(readcount__gt=20))

# 需要查询id大于2或者阅读量大于20的书籍,这时候需要用到Q对象
BookInfo.objects.filter(Q(id__gt=2)|Q(readcount__gt=20))

聚合函数(计算,累计)

聚合函数需要使用 aggregate
语法形式是: aggregte(Xxx('字段'))

python manage.py shell

from book.models import BookInfo
from django.db.models import Sum,Avg,Max,Min,Count

# 当前数据的阅读总量
BookInfo.objects.aggregate(Sum('readcount'))

排序

python manage.py shell

from book.models import BookInfo
# 按阅读量排序
# 升序
BookInfo.objects.all().order_by('readcount')
# 降序
BookInfo.objects.all().order_by('-readcount')

关联查询(多个表)

书籍和人物的关系是 l:n
书籍 中没有任何关于人物的字段
人物 中有关专书籍的字段 book 外键
语法形式
通过书籍查询人物:主表模型.关联模型类名小写_set.all()
通过人物查询书籍:从表模型(实例对象).外键

通过书籍查询人物(一对多):查询书籍为1的所有人物信息

python manage.py shell

from book.models import BookInfo

# 查询书籍
book = BookInfo.objects.get(id=1)
# 根据书籍关联人物信息
book.peopleinfo_set.all()

通过人物查询书籍(多对一):查询人物为1的书籍信息

python manage.py shell

from book.models import PeopleInfo
# 查询人物
person = PeopleInfo.objects.get(id=1)
# 根据人物查询书籍
person.book.name

关联查询的筛选

书籍和人物的关系是 l:n
书籍 中没有任何关于人物的字段
人物 中有关专书籍的字段 book 外键
语法形式
一对多
需要的是图书信息,已知条件是人物信息filter(关联模型类名小写__字段__运算符=值)
需要的是主表数据,已知条件是从表信息filter(关联模型类名小写__字段__运算符=值)

多对一
需要的是人物信息,已知条件是书籍信息filter(外键__字段__运算符=值)
需要是是从表数据,已知条件是主表信息filter(外键__字段__运算符=值)

# 一对多
python manage.py shell

from book.models import BookInfo
# 查询图书,要求图书人物为郭靖
BookInfo.objects.filter(peopleinfo__name__exact='郭靖')
BookInfo.objects.filter(peopleinfo__name='郭靖')
# 查询图书,要求图书中人物的表述包含‘八’
BookInfo.objects.filter(peopleinfo__description__contains='八')
# 多对一
python manage.py shell

from book.models import PeopleInfo
# 查询书名为“天龙八部”的所有人物
PeopleInfo.objects.filter(book__name='天龙八部')
PeopleInfo.objects.filter(book__name_exact='天龙八部')
# 查询困书阅读量大于30的所有人物
PeopleInfo.objects.filter(book__readcount__gt=30)

查询集

查询集:也称查询结果集、QuerySet,表示从数据库中获取的对象集合当调用如下过滤器方法时,Django会返回查询集( 而不是简单的列表 ) :

all():返回所有数据
filter(): 返回满足条件的数据
exclude()返回满足条件之外的数据
order_by(): 对结果进行排序

对查询集可以再次调用过滤馨进行过滤,如:books = BookInfo.objects.filter(readcount__gt=30).order_by(‘pub_date’)
也就息味着查询集可以含有零个、一个或多个过滤器:过滤器基于所给的参数限制查询的结果
从SQL的角度讲,查询集与select语句等价,过滤器像where、 limitorder by子句。

查询集两大特性

惰性执行:创建查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的情况包括送代、序列化、与i合用。例如,当执行books = BookInfo.objects .all()语句时,并未进行数据库查询,只是创建了一个查询集books,继续执行追历选代操作后,才真正的进行了数据库的查询 for book in books : print(book.name)
缓存:使用同一个查询集,第一次使用时会发生数据库的查询,然后Django会把结果缓存下来,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数。

# 该方法每次执行都没有缓存,每次执行都会读取数据库内容
[book.id for book in BookInfo.objects.all()]
[book.id for book in BookInfo.objects.all()]

# 优化后,有缓存,重复使用不会从新读取数据库,提升速率
books = BookInfo.objects.all()
[book.id for book in books]
[book.id for book in books]

限制查询集:可以对查询集进行取下标或切片操作。对查询集进行切片后返回一个新的查询集,不会立即执行查询。

# 不支持负数索引
BookInfo.objects.all()[0:2]

分页

链接:https://docs.djangoproject.com/en/4.2/topics/pagination/

python manage.py shell

from book.models import BookInfo
from django.core.paginator import Paginator

books = BookInfo.objects.all()
# 将数据分页
# object_list 结果集/列表
# per_page  每页多少记录
p = Paginator(books, 2)
# 获取第几页数据
books_page = p.page(1)
books_page[0]

三、视图

项目准备工作

创建项目:django-admin startproject bookmanager
进入项目:cd bookmanager
添加子应用:python manage.py startapp book
在主项目的settings.py中配置
Django框架_第58张图片

在子应用的models.py中定义模型

from django.db import models

class BookInfo(models.Model):
    name = models.CharField(max_length=10, unique=True, verbose_name='名字')  # 唯一
    # 发布日期
    pub_data = models.DateField(null=True)
    # 阅读量
    readcount = models.IntegerField(default=0)
    # 评论量
    commentcount = models.IntegerField(default=0)
    # 是否逻辑删除
    is_delete = models.BooleanField(default=False)

    class Meta:
        # 改表名
        db_table = 'bookinfo'
        # 修改后台admin的显示信息的配置
        verbose_name = 'admin'

    def __str__(self):
        return self.name

class PeopleInfo(models.Model):
    # 有序字典
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    name = models.CharField(max_length=10,verbose_name='名称')
    # 性别
    gender = models.BooleanField(choices=GENDER_CHOICES, default=0)
    description = models.CharField(max_length=200, null=True)
    # 外键
    book = models.ForeignKey(BookInfo, on_delete=models.CASCADE)
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'peopleinfo'
        verbose_name = '人物信息'

    def __str__(self):
        return self.name

在主应用的settings.py中进行数据库相关配置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1', # 主机
        'PORT': '3306',      # 端口
        'USER': 'root',      # 用户名
        'PASSWORD': '123456', # 密码
        'NAME': 'msql',      # 指定数据库
    }
}

同时还要在主应用的__init__.py中添加如下代码

import pymysql
pymysql.install_as_MySQLdb()

接着运行python manage.py makemigrationspython manage.py migrate会生成数据库
然后使用指令在cmd中连接数据库并插入数据

insert into bookinfo(name, pub_data, readcount, commentcount, is_delete) values
('射雕英雄传','1999-1-1','11','22',0),
('天龙八部','1999-11-11','22','33',0),
('笑傲江湖','1999-3-3','55','44',0);

insert into peopleinfo(name, gender, book_id, description, is_delete) values
('郭靖', 1, 1, '降龙十八掌',0),
('黄蓉', 0, 1, '打狗棍法',0),
('乔峰', 1, 2, '降龙十八掌',0),
('段誉', 1, 2, '六脉神剑',0),
('东方不败', 0, 3, '葵花宝典',0);

在子应用的views.py中设置

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.=
def index(request):
    return HttpResponse('index')

在子应用中创建urls.py路由文件

from django.urls import path
from login.views import index


urlpatterns = [
    # 参照:正则;函数
    path('index/', index),
]

运行指令python manage.py runsetver之后,在主应用的urls.py中添加引入该路由

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

urlpatterns = [
    # 参照:正则;函数
    path('admin/', admin.site.urls),
    # 添加一项
    path('', include('login.urls'))
]

浏览http://127.0.0.1:8000/就会出现如下页面
Django框架_第59张图片

允许IP访问

当运行python manage.py runsetver 192.168.0.107:8000指定IP,浏览器可能会出现如下情况
Django框架_第60张图片

这时需要在主应用的settings.py中修改如下内容即可正常访问

# 允许以哪个主机的形式访问后端
# 默认是127.0.0.1,如果改变了需要手动加入
# 如果改变允许方式,需要将运行的ip/域名添加进来
# 安全机制,只能以罗列的来访问
ALLOWED_HOSTS = ['192.168.0.107', '127.0.0.1']

Django框架_第61张图片

配置URLconf

在主应用的settings.py中有如下指定url的配置内容

# 指定URL配置
ROOT_URLCONF = 'bookmanager.urls'

在主应用的urls.py中有路由配置,可以引入到子应用的路由中

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

urlpatterns = [
    path('admin/', admin.site.urls),
    # 引入子应用
    path('', include('book.urls')),
]

在子应用中创建了urls.py,写入了部分路由

from django.contrib import admin
from django.urls import path
from book.views import index

urlpatterns = [
    path('index/', index),
]

reverse路由跳转(利用参数name方便修改URL)

reverse 就是通过 name 来动态获取路径(路由)
如果没有设置namespace 则可以通过name来获取 reverse(name)
如果有设置namespace 则可以通过namespace:name来获取 reverse(namespace:name)

在子应用的urls.py内容如下

from django.contrib import admin
from django.urls import path
from book.views import index

urlpatterns = [
    path('index/', index),
]

在子应用的views.py中内容如下,有几个跳转页面

from django.shortcuts import render, redirect
from django.http import HttpResponse
from book.models import BookInfo

# Create your views here.

def index(request):
    # 登陆成功之后需要跳转到
    return redirect('/index/')
    # 首页注册成功之后需要跳转到首页
    return redirect('/index/')

像上面一样,如果需要修改settings.pyindex路由,则views.py中的index也要一起替换,这时可以用下面的方法
name参数:在路由后面添加个name参数

from django.contrib import admin
from django.urls import path
from book.views import index

urlpatterns = [
    # 可以通过name进行命名,可以通过name找到这个路由
    path('index/', index, name='name1'),
]

views.py中内容如下reverse中的参数为上面name的值

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from book.models import BookInfo

# Create your views here.

def index(request):
	# 路由是动态获取的
    path = reverse('name1')
    # 登陆成功之后需要跳转到
    return redirect(path)
    # 首页注册成功之后需要跳转到首页
    return redirect(path)

防止name重复命名
当上面的name参数有重复的时候,可以在主应用urls.py的include中添加一个参数namespace

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

urlpatterns = [
    path('admin/', admin.site.urls),
    # 引入子应用
    # 在第二个参数添加namespace,这里的name就变成了namespace:name
    # namespace习惯使用子应用名
    path('', include('book.urls', namespace='book')),
]

上面设置了namespace,views.py中就需要如下

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from book.models import BookInfo

# Create your views here.

def index(request):
	# 如果上面使用了namespace参数,这里需要使用namespace:name来获取路由
    path = reverse('book:name1')
    # 登陆成功之后需要跳转到
    return redirect(path)
    # 首页注册成功之后需要跳转到首页
    return redirect(path)

postman工具下载

下载链接:https://www.postman.com/downloads/
下载之后直接双击运行即可

HttpRequest对象(通过位置获取url参数)

关键字参数(url路径)

将url的参数传入视图函数中

子应用的urls.py内容如下,需要使用<>将需要的数据传入index函数中,<>中的内容一定要与index函数里面的一样

from django.contrib import admin
from django.urls import path
from book.views import index

urlpatterns = [
    # http://127.0.0.1:8000/分类id/书籍id/
    # 分组来获取正则中的数据,前面括号括起来的两个参数会传入index函数中
    path('//', index),
]

子应用的views.py中函数,分别对应下面两个参数

def index(request, category_id, book_id):
    return HttpResponse(category_id+'/'+book_id)

浏览页面时,后面可以带一定的数据
Django框架_第62张图片

GET方式传递查询字符串

链接号的前面是路由,后面表示以get方式传递的参数,称为查询字符串
在登陆的时候会输入用户名和密码,理论上用户名和密码都应该以POST方式进行传递
为了理解,以get请求传递用户名和密码

这里获取后面的参数访问http://127.0.0.1:8000/1/100/?username=itcast&password=123&username=python时得到对应的输出结果,下面为子应用的views.py内容

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from book.models import BookInfo

# 运行时访问http://127.0.0.1:8000/1/100/?username=itcast&password=123&username=python
def index(request, category_id, book_id):
    query_params = request.GET
    print(query_params)  # 
    # 当一键多值得时候只能获取一个值,要获取一键多值得时使用getlist方法
    print(query_params['username'])   # python
    print(query_params.get('username'))  # 同上
    # 获取一键多值
    print(query_params.getlist('username'))    # ['itcast', 'python']
    return HttpResponse(category_id+'/'+book_id+' ' + str(query_params))

POST表单数据

当带参数进行post请求的时候(postman应用),会出现下面的问题
Django框架_第63张图片

在这里插入图片描述

意思是禁止访问,这时需要在主应用的settings.py中注释掉一行代码即可正常浏览

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',
]

子应用的views.py内容

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from book.models import BookInfo

# Create your views here.
def index(request, category_id, book_id):
    data = request.POST
    print(data)  # 
    return HttpResponse(category_id+'/'+book_id)

POST json数据

PostMan工具操作
Django框架_第64张图片

子应用的views.py内容

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from book.models import BookInfo
import json

# Create your views here.

def index(request, category_id, book_id):
    data = request.body
    print(data)  # b'{\r\n    "username":"itcast",\r\n    "password":"123"\r\n}'
    print(data.decode())  # 输出JSON形式的字符串
    '''
    {
        "username":"itcast",
        "password":"123"
    }
    '''
    # json.dumps 将字典转化为JSON形式的字符串
    # json.loads 将JSON形式的字符串转化为字典
    data = json.loads(data)
    print(data)  # {'username': 'itcast', 'password': '123'}
    return HttpResponse(category_id+'/'+book_id)

请求头

浏览器访问127.0.0.1:8000/1/100/,然后会有输出

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from book.models import BookInfo

def index(request, category_id, book_id):
    # 打印请求头信息
    print(request.META)
    print(request.META['CONTENT_TYPE'])
    return HttpResponse(category_id+'/'+book_id)

其他常用HttpRequest对象属性

method:一个字符串,表示请求使用的HTTP方法,常用值包括 :GET、POST
user :请求的用户对象。
path : 一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
encoding :一个字符串,表示提交的数据的编码方式。如果为None则表示使用浏览器的默认设置,一般为utf-8。这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值·
FILES:一个类似于字典的对象,包会所有的上传文件

def index(request, category_id, book_id):
    print(request.method)
    print(request.user)
    print(request.path)
    print(request.encoding)
    return HttpResponse(category_id+'/'+book_id)

HttpResponse对象

HttpResponse

视图在接收请求并处理后,必须返回HttpResponse对象或子对象。HttpRequest对象由Django创建,HttpResponse对象由开发人员创建
可以使用django.http.HttpResponse来构造响应对象
HttpResponse(content-响应体,content_type-响应体数据类型,status-状态码)

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.

def index(request):
    # 参数content:传递字符串
    # 参数status:只能是系统规定的
    # 参数content_type:是一个MIME类型
    #   语法形式:大类/小类 如:text/html   text/css  text/javascript
    #            application/json   image/png  image/gif  image/jpeg
    return HttpResponse('data', statue=400)
    # return HttpResponse('data', statue=400, content_type='')

JsonResponse

返回字典类型数据
子应用views.py内容如下

from django.http import JsonResponse
def index(request):
    data = {'name':'itcast'}
    return JsonResponse(data)

Django框架_第65张图片

重定向(页面跳转)

子应用views.py内容如下,浏览之后会自动跳转到http://www.itcast.cn

from django.shortcuts import render, redirect

# Create your views here.
from django.http import JsonResponse
def index(request):
    # 页面跳转到http://www.itcast.cn
    return redirect('http://www.itcast.cn')
from django.shortcuts import render, redirect, reverse

# Create your views here.
from django.http import JsonResponse
def index(request):
    # 页面跳转到http://www.itcast.cn
    path = reverse('book:index')
    return redirect(path)

状态保存

浏览器请求服务器是无状态的。
无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求·
无状态原因:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。
有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等
实现状态保持主要有两种方式 :
——在客户端存储信息使用 cookie
——在服务器端存储信息使用 Session

Cookie

Cookie是保存在客户端
Cookie是基于域名(IP)的

Cookie流程

第一次请求过程
1.我们的浏览器第一次请求服务器的时候,不会携带任何cookie信息
2.服务器接收到请求之后,发现 请求中没有任何cookie信息
3.服务器设置一个cookie.这个cookie设置在响应中
4.我们的浏览器接收到这个相应之后,发现响应中有cookie信息,浏览器会将cookie信息保存起来
第二次及其之后的过程
5当我们的浏览器第二次及其之后的请求都会携带cookie信息
6.我们的服务器接收到请求之后,会发现请求中携带的cookie信息,这样的话就认识是谁的请求了

views.py

from django.http import HttpResponse

def set_cookie(request):
    # 1.先判断有没有Cookie信息
    # 先假设没有
    # 2.获取用户名
    username = request.GET.get('username')
    # 3.因为我们假设没有cookie信息,我们服务器就要设置cookie信息
    response = HttpResponse('set_cookie')
    # key,value
    response.set_cookie('username', username)
    # 4.返回响应
    return response

def get_cookie(request):
    '''
    第二次及其之后请求
    '''
    # 服务器接收cookie
    cookies = request.COOKIES
    # cookies 是一个字典
    username = cookies.get('username')
    # 得到用户信息可以继续其他业务
    
    return HttpResponse('get_cookie')

urls.py

from django.contrib import admin
from django.urls import path
from book.views import index

urlpatterns = [
    path('set_cookie/', set_cookie),
    path('get_cookie/', get_cookie),
]

设置Cookie过期时间:使用参数max_age,单位为秒

def set_cookie(request):
    # 1.先判断有没有Cookie信息
    # 先假设没有
    # 2.获取用户名
    username = request.GET.get('username')
    # 3.因为我们假设没有cookie信息,我们服务器就要设置cookie信息
    response = HttpResponse('set_cookie')
    # key,value
    # max_age为秒数,设置Cookie过期时间
    response.set_cookie('username', username, max_age=600)
    # 4.返回响应
    return response

删除Cookieresponse.delete_cookie(key)或者response.set_cookie(key, value, max_age=0)

def set_cookie(request):
    username = request.GET.get('username')
    response = HttpResponse('set_cookie')
    response.set_cookie('username', username, max_age=600)
    # 删除cookie
    response.delete_cookie('username')
    # 或者
    response.set_cookie('username', username, max_age=0)
    # 4.返回响应
    return response

Session

settings.py中默认启用了session
Django框架_第66张图片

Session保存在服务器
session需要依赖于cookie
如果浏览器禁用了cookie,则session不能实现
项目的数据库中会有个django_session表格保存session相关数据(session_key,session_data,expire_date)(设置session的时候将数据保存到数据库中
Django框架_第67张图片

session流程

第一次请求:
1.我们第一次请求的时候可以携带一些信息(用户名/密码) cookie中没有任何信息
2.当我们的服务器接收到这个请求之后,进行用户名和密码的验证,验证没有问题可以设置session信息
3.在设置session信息的同时(session信息保存在服务器端),服务器会在响应头中设置一个session id的cookie信息(由服务器设置)
4.客户端(浏览器)在接收到响应之后,会将cookie信息保存起来(保存 sessionid的信息)
第二次及其之后的请求:
5.第二次及其之后的请求都会携带 session id信息
6.当服务器接收到这个请求之后,会获取到sessionid信息,然后进行验证,验证成功,则可以获取 session信息(session信息保存在服务器端)

第一次请求:
1.我们第一次请求的时候可以携带一些信息(用户名/密码) cookie中没有任何信息
2.当我们的服务器接收到这个请求之后,进行用户名和密码的验证,验证没有问题可以设置session信息
3.在设置session信息的同时(session信息保存在服务器端),服务器会在响应头中设置一个session id的cookie信息(由服务器设置)
4.客户端(浏览器)在接收到响应之后,会将cookie信息保存起来(保存 sessionid的信息)
第二次及其之后的请求:
5.第二次及其之后的请求都会携带 session id信息
6.当服务器接收到这个请求之后,会获取到sessionid信息,然后进行验证,验证成功,则可以获取 session信息(session信息保存在服务器端)

views.py内容如下

def set_session(request):
    '''
    第一次请求:
    1.我们第一次请求的时候可以携带一些信息(用户名/密码) cookie中没有任何信息
    2.当我们的服务器接收到这个请求之后,进行用户名和密码的验证,验证没有问题可以设置session信息
    3.在设置session信息的同时(session信息保存在服务器端),服务器会在响应头中设置一个session id的cookie信息
    4.客户端(浏览器)在接收到响应之后,会将cookie信息保存起来(保存 sessionid的信息)
    '''
    # 1.cookie中没有任何信息
    print(request.COOKIES)
    # 2.对用户名和密码进行验证
    # 假设认为用户名和密码正确
    user_id = 6666
    # 3.设置session信息(设置的时候将数据保存到数据库中,设置cookie信息是以sessionid为key)
    # request.session 理解为字典
    request.session['user_id'] = user_id
    # 4.返回响应
    return HttpResponse('set_session')

def get_session(request):
    '''
    第二次及其之后的请求**:
    5.第二次及其之后的请求都会携带 session id信息
    6.当服务器接收到这个请求之后,会获取到sessionid信息,然后进行验证,验证成功,则可以获取 session信息(session信息保存在服务器端)
    '''
    # 请求都会携带 session_id信息
    print(request.COOKIJES)
    # 2,会获取到sessionid信息,然后进行验证
    # 验证成功,可以获取 session信息

    # request.session 字典
    user_id = request.session['user_id']
    user_id = request.session.get('user_id')

    # 3.返回响应
    return HttpResponse('get_session')

类视图

将两个视图转化为一个视图

登录页面
GET请求是获取登录的页面
POST请求是验证登录(用户名和密码是否正确)

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
# GET 请求获取登入页面
def show_login(request):

    return render(request)

# POST 请求是验证登入(用户名和密码是否正确)
def veri_login(request):
    return redirect('首页')

转化为一个视图如下

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse

# 由连个视图变为一个视图
def login(request):
    # 区分业务逻辑
    if request.method == 'GET':
        # GET请求获取登入页面
        return render(request)
    else:
        # POST 请求是验证登入(用户名和密码是否正确)
        return redirect('首页')

类视图面向对象

类视图是采用面向对象的思路
一、定义类视图
1、继承自view(from django.views import View)
2、不同的请求方式有不同的业务逻辑
类视图的方法就直接采用http的请求名字作为我们的函数名,例如:get,post,put,patch等(as_view()中)
3、类视图的方法的第二个参数必须是请求实例对象
类视图的方法必须有返回值,返回值是HttpResponse及其子类

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from django.views import View

class LoginView(View):

    def get(self,request):
        return HttpResponse('get')

    def post(self,request):
        return HttpResponse('post')

类视图URL引导

from django.urls import path
from book.views import index,LoginView
# as_view函数会根据请求方式的不同调用上面不同的函数,如果是GET请求,则调用上面的get函数
urlpatterns = [
    path('login/', LoginView.as_view()),
]

需求如下

个人中心页面 ————必须登入才能显示
GET方式展示个人中心
POST实现个人中心信息修改
定义类视图

views.py代码如下

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse


from django.views import View

class CenterView(View):
    def get(self, request):
        return HttpResponse('个人中心展示')

    def post(self, request):
        return HttpResponse('个人中心信息修改')

urls.py

from django.urls import path
from book.views import index,CenterView

urlpatterns = [
    path('center/', CenterView.as_view()),
]

上面浏览后在没有登陆的情况下还是可以正常浏览,效果如下
Django框架_第68张图片

由于展示个人中心页面必须登入才能显示所以需要做如下修改,这里可以判断用户是否登录没有登录的情况下,系统框架会自动跳到登入的界面

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse


from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin

class CenterView(LoginRequiredMixin, View):
    def get(self, request):
        return HttpResponse('个人中心展示')

    def post(self, request):
        return HttpResponse('个人中心信息修改')

在加了如上代码之后,浏览http://127.0.0.1:8000/center/之后,在没有登入的情况下,会自动跳转到登录界面(这里没有导入登录界面路由),结果如下
Django框架_第69张图片

中间件

中间件的作用:每次请求和响应的时候都会调用

Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理对程,修改Django的输入或输出·中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性:
我们可以使用中间件,在Diango处理视图的不同阶段对输入或输出进行干预·

settings.py中有这么一段

# 中间件
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',
]

中间件的定义:定义一个中间件工厂函数,然后返回一个可以被调用的中间件。中间件工厂函数需要接收一个可以调用的get_response对象·返回的中间件也是一个可以被调用的对象,并且像视图一样需要接收一个request对象参数,返回一个response对象·
在子应用中创建middleware.py文件,内容如下(中间件的定义

def simple_middleware(get_response):
    def middleware(request):
        print('before request')
        # 响应前
        response = get_response(request)
        # 响应后
        print('after request')
        return response
    return middleware

在settings.py中添加middleware文件

# 中间件
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',
    'book.middleware.simple_middleware',   # 添加这行
]

浏览页面,终端就会打印如下内容
Django框架_第70张图片

实例:可以判断每次请求是否携带了cookie中的某些信息,通常如果不使用中间件,要在浏览中判断是否有cookie,需要在每个函数中都添加判断的代码,如下
views.py

from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin

class CenterView(LoginRequiredMixin, View):
    def get(self, request):
        username = request.COOKIES.get('username')
        if username is None:    # 添加判断
            print('username is None')
        return HttpResponse('个人中心展示')

    def post(self, request):
        username = request.COOKIES.get('username')
        if username is None:    # 添加判断
            print('username is None')
        return HttpResponse('个人中心信息修改')

可以利用中间件,建立个中间件文件,在中间件中加入如下代码,则在上面的函数中就不需要添加判断
views.py

from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin

class CenterView(LoginRequiredMixin, View):
    def get(self, request):
        return HttpResponse('个人中心展示')

    def post(self, request):
        return HttpResponse('个人中心信息修改')

middleware.py

def simple_middleware(get_response):
    def middleware(request):
        # 添加判断
        username = request.COOKIES.get('username')
        if username is None:
            print('username is None')
            
        print('before request')
        # 响应前
        response = get_response(request)
        # 响应后
        print('after request')
        return response
    return middleware

在上面的实例中,如果没有登入,可以直接加个return返回某页面,代码如下

from django.http import HttpResponse
def simple_middleware(get_response):
    def middleware(request):
        username = request.COOKIES.get('username')
        if username is None:
            print('username is None')
            # 没有登入直接返回
            return HttpResponse('没有登入')
        
        print('before request')
        # 响应前
        response = get_response(request)
        # 响应后
        print('after request')
        return response
    return middleware

效果如下
Django框架_第71张图片

多个中间件顺序:请求前的执行顺序是按照注册的顺序从上往下(settings.py中),响应后的顺序是从下往上(注册的反顺序)
在middleware.py中定义多个中间件

def simple_middleware1(get_response):
    def middleware(request):
        print('before request 11111')
        # 响应前
        response = get_response(request)
        # 响应后
        print('after request 11111')
        return response
    return middleware

def simple_middleware2(get_response):
    def middleware(request):
        print('before request 22222')
        # 响应前
        response = get_response(request)
        # 响应后
        print('after request 22222')
        return response
    return middleware

在settings.py中引入(注册顺序右上到下

# 中间件
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',
    
    'book.middleware.simple_middleware1',   # 添加这行
    'book.middleware.simple_middleware2',   # 添加这行
]

输出结果如下

before request 11111
before request 22222
after request 22222
after request 11111

模板

Django使用自带模板,在工程中创建模板目录templates,在这个目录里面创建index.html文件,内容额如下,这里写的是固定的,算不撒上是模板,模板需要里面的内容可以灵活变动,如下面的itcast可以根据信息的不同,显示不同内容,需要特殊语法将数据库或程序中的内容导入其中

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<a href="">itcasta>
body>
html>

基本配置

在settings.py中配置文件修改TEMPLATES配置项的DIRS值

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',
            ],
        },
    },
]

子应用views.py

from django.shortcuts import render

class HomeView(View):
    def get(self, request):
        return render(request, 'index.html')

子应用urls.py

from django.urls import path
from book.views import HomeView

urlpatterns = [
    path('index/', HomeView.as_view()),
]

使用模板

views.py

from django.shortcuts import render
from django.views import View

class HomeView(View):
    def get(self,request):
        # 1.获取数据
        username = request.GET.get('username')
        # 2.组织数据
        context = {
            'username': username
        }
        return render(request, 'index.html', context=context)

templates中的index.html内容如下(使用{{ username }}获取上面传入的数据)

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<a href="">{{ username }}a>
body>
html>

浏览链接http://127.0.0.1:8000/index/?username=abcd就会显示username后面的数据
Django框架_第72张图片

模板语法

下面列举了列表,遍历,判断,索引展示
注意:运算符两侧必须要有空格
views.py

from django.shortcuts import render
from django.views import View

# Create your views here.
class HomeView(View):
    def get(self,request):
        # 1.获取数据
        username = request.GET.get('username')
        # 2.组织数据
        context = {
            'username': username,
            'age': 10,
            'friend': ['toy', 'jack'],
            'scores': {
                'math': 100,
                'english': 90,
            }
        }
        return render(request, 'index.html', context=context)

index.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<a href="">{{ username }}a>
<hr>
年龄:{{ age }}
<hr>
朋友:{{ friend }}
<hr>
朋友:{{ friend.1 }}
<hr>
分数:{{ scores.math }}
<hr>
遍历索引朋友:{% for item in friend %}
<li>{{ forloop.counter }}{{ item }}li>
{% endfor %}
<hr>
{% if age > 10 %}
    大于10岁
{% else %}
    不大于10岁
{% endif %}

body>
html>

效果如下
Django框架_第73张图片

过滤器
过滤器语法形式:变量|过滤器:参数
过滤器有几个常用的

safe,禁用转义,告诉模板这个变量是安全的,可以解释执行
length,长度,返回字符丰包含字符的个数,或列表、元组、字典的元素个数
default,默认值,如果变量不存在时则返回默认值(date|default:'默认值'
date,日期,用于对日期类型的值进行字符串格式化(value|data:"Y年m月j日 H时i分s秒"),常用的格式化字符如下 :

字符 含义 解释
Y 格式4位(y两位)
m 01,02,12
d 01,02
j 1,2
H 24小时制(h12小时制)
i 0-59
s 0-59

views.py

from django.shortcuts import render
from django.views import View
import datetime

class HomeView(View):
    def get(self,request):
        username = request.GET.get('username')
        context = {
            'datetime': datetime.datetime.now(),
        }
        return render(request, 'index.html', context=context)
    
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
日期:{{ datetime|date:'Y m d' }}
body>
html>

Django框架_第74张图片

转义字符如下,按如下方式书写,会有转义字符
views.py

class HomeView(View):
    def get(self,request):
        # 1.获取数据
        username = request.GET.get('username')
        # 2.组织数据
        context = {
            'desc': ''
        }
        return render(request, 'index.html', context=context)

index.html

<body>
转义字符:{{ desc }}
body>

按上面书写会是这种效果,没有弹窗,会将scrpipt转化为字符串显示
Django框架_第75张图片

经过如下修改,就会弹出弹框

<body>
转义字符:{{ desc|safe }}
body>

Django框架_第76张图片

无定义的量默认值长度
在views.py中没有定义的变量

<body>
无定义变量:{{ abc|default:'默认值' }}
<hr>
长度:{{ friend|length }}
body>
class HomeView(View):
    def get(self,request):
        # 1.获取数据
        username = request.GET.get('username')
        # 2.组织数据
        context = {
            'friend': ['toy', 'jack'],
        }
        return render(request, 'index.html', context=context)

Django框架_第77张图片

模板继承

模板继承和类的继承含义是一样的,主要是为了提高代码重用,减轻开发人员的工作量
父标签
如果发现在多个模板中某些内容相同,那就应该把这段内容定义到父模板中。
标签block: 用于在父模板中预留区域,留给子模板填充差异性的内容,名字不能相同·为了更好的可读性,建议给endblock标签写上名字,这个名字与对应的block名字相同,父模板中也可以使用上下文中传递过来的数据。
字标签
标签extends: 继承,写在子模板文件的第一行
Django框架_第78张图片
子模版不用填充父模版中的所有预留区域,如果子模版没有填充,则使用父模版定义的默认值

这个页面和另一个页面某个部分是一样的模板格式
在template目录中创建一个基础文件base.html,代码如下

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}Title{% endblock title %}title>
head>
<body>
{% block header %}
<h1>顶部h1>
{% endblock header %}

{% block main %}
<h1>主要部分h1>
{% endblock main %}

{% block footer %}
<h1>底部h1>
{% endblock footer %}
body>
html>

创建detail.html如下

把继承的模板写在最上面
需要改哪里,直接实现block,进行替换,没写的就还是原先base.html的内容
不需要的部分直接用空白block进行替换
(这里替换了标题,导航栏主题,删除了底部,标题没有变动)

{% extends 'base.html' %}

{% block title %}
替换标题
{% endblock title %}

{% block main %}
<a href="">替换主体a>
{% endblock main %}

{% block footer %}{% endblock %}

Django框架_第79张图片

Django使用jinja2模板

jinja2是 Python 下一个被广泛应用的模板引擎,是由Python实现的模板语言,他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能,尤其是Flask框架内置的模板语言
由于django默认模板引擎功能不齐全,速度慢,所以我们也可以在Django中使用jinja2, jinja2宣称比django默认模板引擎快10-20倍
Django主流的第三方APP基本上也都同时支持Diango默认模板及inja2,所以要用inia2也不会有多少障碍。

安装jinja2模板:pip install jinja2
jiaja2配置
在settings.py中配置

TEMPLATES = [
    {
        # 'BACKEND': 'django.template.backends.django.DjangoTemplates',  # 默认引擎
        'BACKEND': 'django.template.backends.jinja2.Jinja2',  # 修改为Jinja2模板
        'DIRS': [os.path.join(BASE_DIR, 'template')],
        'APP_DIRS': True,
        'OPTIONS': {
            'environment': 'jinja2.Environment',  # 添加这行  默认的,可加可不加
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },# 如果报错,原始的代码复制到下面
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',  # 默认引擎
        'DIRS': [os.path.join(BASE_DIR, 'template')],
        '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',
            ],
        },
    },
]

直接使用上面的index.html会出现错误

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<a href="">{{ username }}a>
<hr>
年龄:{{ age }}
<hr>
朋友:{{ friend }}
<hr>
朋友:{{ friend.1 }}
<hr>
分数:{{ scores.math }}
<hr>
遍历索引朋友:{% for item in friend %}
<li>{{ forloop.counter }}{{ item }}li>
{% endfor %}
<hr>
{% if age > 10 %}
    大于10岁
{% else %}
    不大于10岁
{% endif %}
<hr>
日期:{{ datetime|date:'Y m d' }}
转义字符:{{ desc|safe }}
无定义变量:{{ abc|default:'默认值' }}
<hr>
长度:{{ friend|length }}
body>
html>

Django框架_第80张图片

这是因为jiaja2的语法和上面模板的语法有些区别
区别在于过滤器不同,上面的模板是forloop,jiaja2是loop
jiaja2过滤器
index.html

<body>

日期:{{ date(datetime) }}
body>
from django.views import View
import datetime

class HomeView(View):
    def get(self,request):
        context = {
            'datetime': datetime.datetime.now(),
        }
        return render(request, 'index.html', context=context)

有上面的还不够,会显示date未定义,这时在子应用中创建jinja2_env.py文件,内容如下

from django.template.defaultfilters import date
from jinja2 import Environment

def environment(**option):
    # 1.创建Environment实例
    env = Environment(**option)
    # 2.指定jinja2的函数指向django的指定过滤器
    env.globals.update({
        'date': date
    })
    # 3.返回Environment实例
    return env

然后修改配置settings.py

TEMPLATES = [
    {
        # 'BACKEND': 'django.template.backends.django.DjangoTemplates',  # 默认引擎
        'BACKEND': 'django.template.backends.jinja2.Jinja2',  # 修改为Jinja2模板
        'DIRS': [os.path.join(BASE_DIR, 'template')],
        'APP_DIRS': True,
        'OPTIONS': {
            # 'environment': 'jinja2.Environment',  # 添加这行  默认的,可加可不加
            'environment': 'book.jinja2_env.environment',  # 指定jinja2的环境
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },# 如果报错,原始的代码复制到下面
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',  # 默认引擎
        'DIRS': [os.path.join(BASE_DIR, 'template')],
        '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',
            ],
        },
    },
]

然后就会出现内容
Django框架_第81张图片
要显示特定的格式,在后面和之前一样添加参数

<body>

日期:{{ date(datetime,'Y m d') }}
body>

Django框架_第82张图片

自定义过滤器

from jinja2 import Environment

def environment(**option):
    # 1.创建Environment实例
    env = Environment(**option)
    # 2.将自定义过滤器添加到环境中
    env.filters['do_listreverse'] = do_listreverse
    # 3.返回Environment实例
    return env

# 自定义过滤器
def do_listreverse(li):
    if li == 'B':
        return "abcd"

CSRF(跨站请求伪造)

CSRF 指攻击者盗用了你的身份,以你的名义发送恶意请求。包括:以你名义发送邮件,发消息山盗取你的账号,甚至于购买商品,虚拟货币转账…
造成的问题 :个人隐私泄露以及财产安全。

Django框架_第83张图片
生成随机码
csrf_token放入cookie是同源策略的原因,黑客(钓鱼)网站是用于获取不到我们当前网站的cookie信息的

    def get(self, request):
        from django.middleware.csrf import get_token
        # 生成随机码
        csrf_token = get_token(request)
        response = render(request, 'index.html', context={'csrf_token': csrf_token})
        # 将验证码保存至cookie中
        response.set_cookie('csrftoken', csrf_token)
        return response

获取用户输入的随机码并验证

    def index(self, request):
        # 获取用户数据
        user_token = request.POST.get('csrftoken')
        to_account = request.POST.get('to_account')
        money = request.POST.get("money")
        # 获取系统生成的验证码
        server_token = request.COOKIES.get('csrf_token')
        # 输入的验证码和系统生成的验证
        if user_token != server_token:
            return HttpResponse('输入错误')

上面获取数据是通过name属性获取的

<body>

<input type="hidden" name="csrftoken">
<input type="text" name="to_account">
<input type="number" name="money">
body>

:是协议、域名、端口号组成
同源策略:同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。

session保存至redis中

session数据的保存、获取、删除(views.py)

# 增加数据
class SetSession(View):
    def get(self, request):
        request.session['name'] = 'icast'
        return HttpResponse('abc')

# 获取数据
class GetSession(View):
    def get(self, request):
        name = request.session['name']
        return HttpResponse('abc')

# 删除数据
class DelSession(View):
    def get(self, request):
        # 删除一条数据
        del request.session['name']
        # 删除session所有数据
        # request.session.clear()
        # 把数据库/redis中的key都删除了
        # request.session.flush()
        return HttpResponse('abc')

# session时间,到了时间自动删除
class DelSession(View):
    def get(self, request):
        # 设置session时间,默认两周
        request.session.set_expiry(10)
        return HttpResponse('abc')

session数据存储位置
在settings.py中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等

保存在数据库中,如下设置可以写,也可以不写,这是默认方式

SESSION_ENGINE=‘django.contrib.sessions.backends.db’
如果保存在数据库中,需要在INSTALLED_APPS中安装Session应用
INSTALLED_APPS = [

‘django.contrib.sessions’,

]
Django框架_第84张图片

本地缓存:存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快

SESSION_ENGINE=‘django.contrib.sessions.backends.cache’

混合缓存:优先从本机内存中存取,如果没有则从数据库中存取

SESSION_ENGINE=‘django.contrib.sessions.backends.cached_db’

Redis:在redis中保存session,需要引入第三方扩展,我们可以使用django-redis来解决。
django-redis链接:https://django-redis-chs.readthedocs.io/zh_CN/latest/

安装扩展:pip install django-redis
配置settings.py内容如下

# caches缓存
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

CSRF的django使用

login.html

<body>

<from action="" method="post">
    <input type="text" name="money">
    <input type="submit" value="提交">
from>
body>

urls.py

from book.views import LoginView

urlpatterns = [
    path('login/', LoginView.as_view()),
]

views.py

class LoginView(View):
    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        return HttpResponse('post')

在上面的基础上,浏览链接输入内容后点击提交会报错,需要在login.html中加入如下代码

<body>

<from action="" method="post">
    {% csrf_token %}
    <input type="text" name="money">
    <input type="submit" value="提交">
from>
body>

然后点击提交,会跳转到post请求中去

你可能感兴趣的:(Python,Django,django,python,后端)