Python:Django3.1 框架学习笔记

Django框架符合的是(MVT模型)–>Model,View,Template

文章目录

  • Django框架符合的是(MVT模型)-->Model,View,Template
  • 1. 创建项目
    • 确认项目是否创建成功
  • 2. 创建项目应用
  • 3.建立项目与应用之间的联系(在setting.py中注册应用)
  • 4.Django核心----ORM模型
  • 5.设计模型类和表(Models 数据库操作)
    • 模型类设计格式
    • 模型类字段类型和字段选项
    • 与数据库的交互流程(生成迁移文件,文件迁移):
    • 元选项(为了避免改了包名导致在数据库中找不到对应生成的表)
  • 6.通过模型类操作数据表
    • 创建一对多关系---外键的使用(这里再定义一个英雄模型类,类中hbook为BookInfo的外键)
    • 创建多对多关系
    • 创建一对一关系
  • 7.关于Django 管理页面
    • 本地化
    • 创建一个管理员账号
    • 启动开发服务器
    • 将后台管理页面中的数据表以标题的形式展现
    • 自定义后台模型管理类
  • 8.将默认数据库sqlite3换成MySQL
  • 9.视图文件的使用
    • path()函数传递了四个参数,两个是必需的:路由和视图,两个是可选的:kwargs 和 name.
    • 利用path()和re_path(),在url中取特定的不固定页面
    • 关闭浏览器页面的DEBUG显示以及错误视图(404和500)
    • 自定义错误视图
    • 关于返回对象request的属性:(属性基本都是只读的,无法进行修改,除encoding和session)
    • 关于返回对象request的请求提交参数的方法(GET,POST)
  • 10. 静态文件
  • 11. Ajax请求
    • 关于Ajax同步与异步
    • Ajax登录案例代码
      • 用表单(< form >)完成登录案例
      • 用Ajax完成登录案例
    • 登录效验失败的解决方法(csrf防护及防御原理)
  • 12. 状态保持
    • Cookie
    • 登录案例--通过cookie记住用户名和密码
    • session
    • 通过HttpRequest对象的session属性进行读写操作
    • 登录案例--记住用户登录状态,下次访问直接登录跳转不必输入用户和密码
    • cookie和session的区别和应用场景
  • 13.模板
    • 13.1 模板语言
      • 13.1.1 模板变量及解析顺序
      • 13.1.2 模板标签
      • 13.1.3 模板过滤器
      • 自定义过滤器
      • 13.1.4模板注释
      • 13.1.5 模板继承
      • 13.1.6 html转义
    • 13.2 模板目录(templates)有两种创建路径:
    • 13.3 模板文件加载顺序
  • 14.页面重定向(from django.shortcuts import redirect)
  • 15. 中间件
    • 15.1 使用中间件
  • 15. 上传图片
    • 15.1 上传图片时必要的配置
    • 15.2 从后台管理页面上传:
    • 15.3 浏览器自定义页面上传图片
  • 16. 分页
    • 16.1 关于分页的方法和属性
  • 16. Django自带缓存
    • 设置缓存
  • .MVT综合代码实例(test1为主项目,booktest为应用)
    • booktest/admin.py
    • booktest/models.py
    • booktest/urls.py
    • booktest/views.py
    • test1/__ init__.py
    • templates/booktest/books_display.html
    • templates/booktest/hero_display.html
    • templates/booktest/area_display.html
    • test1/urls

·

1. 创建项目

命令: django-admin startproject 项目名称

创建好后,该项目目录下的各文件说明
Python:Django3.1 框架学习笔记_第1张图片
● 最外层test1为该项目的容器

manage.py: 一个可以管理Django项目的命令工具

● 里面一层的test1目录包含这个项目的内容,是一个纯Python包,当引用这个项目内部任何东西时需要用到的包名。(比如test1.urls)

__ init__.py: 一个空文件,告诉python这个目录是一个python包。

settings.py: Django的配置文件。

urls.py: Django项目的URL声明,如同网站的”目录“。

asgi.py: 作为你的项目的运行在ASGI兼容的Web服务器上的入口。

wsgi.py: 作为你的项目的运行在WSGI兼容的Web服务器上的入口即web服务器和Django交互的入口。

·

确认项目是否创建成功

$ python3 manage.py runserver 【ip:端口】(默认端口8000)

启动的是Django自带的用于开发的简易服务器,是一个用python写的轻量级的web服务器,在这个内置服务器中可以快速的开发出想要的东西。
Python:Django3.1 框架学习笔记_第2张图片

·

2. 创建项目应用

一个项目由很多个项目应用组成,每一个应用完成一个特定的功能。
创建应用的命令为:

python3 manage.py startapp 应用名

创建好后,该应用目录下的各文件说明:

Python:Django3.1 框架学习笔记_第3张图片

admin.py: 网站后台管理相关的文件。
apps.py: 该应用程序的配置信息。
__ init__.py: 一个空文件,告诉python这个目录是一个python包。
models.py: 写和数据库项目的内容。
test.py: 写测试代码的文件。
view.py: 视图文件,接收请求,进行处理,与M和T进行交互,返回应答。定义处理函数,视图函数。

·

3.建立项目与应用之间的联系(在setting.py中注册应用)

当在项目中创建了一个应用后,这个项目本身并不知道该应用的存在,需要在项目的setting.py中,对应用进行注册

setting.py文件里的INSTALL_APPS()中增加创建的应用名称:
(我这里新创建的应用名称为booktest)

Python:Django3.1 框架学习笔记_第4张图片

·

·

4.Django核心----ORM模型

ORM模型全名为 Object-Relation-Mapping

其作用主要是通过类和对象实现对数据库的操作

另一个作用:根据设计的类生成数据库的表

ORM的原理是利用python中的 元类 进行设计,将数据库增删改查的语句封装起来,通过类和对象对方法的引用实现对数据库的操作

·

·

5.设计模型类和表(Models 数据库操作)

·

模型类设计格式

● 首先在应用文件里的models.py文件中设计模型类(必须继承models.Model类)

● 模型类属性命名限制:

1)不能是python的保留关键字。

2)不允许使用连续的下划钱(如: bpud__date),这是由django的查询方式决定的。

3)定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:

属性名=models.字段类型(选项)

模型类字段类型和字段选项

详细点击
Django3.1官方文档描述的字段类型和选项大全

常用字段类型:

类型 描述
AutoField 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性。
BooleanField 布尔字段,值为True或False。
NullBooleanField 支持Null、True、False三种值。
CharField(max_length=最大长度) 字符串。参数max_length表示最大字符个数。
TextField 大文本字段,一般超过4000个字符时使用。
IntegerField 整数
DecimalField(max_digits=None, decimal_places=None) 十进制浮点数。参数max_digits表示总位。参数decimal_places表示小数位数。
FloatField(精度没有DecimalField精确) 浮点数。参数同上
DateField:([auto_now=False, auto_now_add=False]) 日期。1)参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false。2) 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。3)参数auto_now_addauto_now相互排斥的,组合将会发生错误。
TimeField 时间,参数同DateField。
DateTimeField 日期时间,参数同DateField。
FileField 上传文件字段。
ImageField 继承于FileField,对上传的内容进行校验,确保是有效的图片。

·

常用字段选项:

选项名 描述
default 默认值。设置默认值。
primary_key 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用。
unique 如果为True, 这个字段在表中必须有唯一值,默认值是False。
db_index 若值为True, 则在表中会为此字段创建索引,默认值是False。
db_column 字段的名称,如果未指定,则使用属性的名称。
null 如果为True,表示允许为空,默认值是False。
blank 如果为True,则该字段允许为空白,默认值是False。

注:字段选项中 null 是数据库范畴的概念,blank 是后台管理页面表单验证范畴的。

经验:
当修改模型类之后,如果添加的选项不影响表的结构,则不需要重新做迁移,商品的选项中defaultblank不影响表结构。

·
实例:

Python:Django3.1 框架学习笔记_第5张图片

·

·

与数据库的交互流程(生成迁移文件,文件迁移):

● 将模型类生成表:

  1. 生成迁移文件:

$ python3 manager.py makemigrations在这里插入图片描述

之后在booktest(创建的应用目录)中的migrations目录下出现了一个文件 0001_initial.py
该文件就是迁移文件

从文件中可以看到程序会自动生成一个id主键

Python:Django3.1 框架学习笔记_第6张图片
·

2)执行迁移文件

$ python3 manage.py migrate
Python:Django3.1 框架学习笔记_第7张图片

这项命令的作用是根据迁移文件生成相应的数据库里的表

·

setting.py文件中可以看到Django默认使用的数据库表是 sqlite3

Python:Django3.1 框架学习笔记_第8张图片

·

元选项(为了避免改了包名导致在数据库中找不到对应生成的表)

迁移文件进行迁移后,在数据库中生成的表名依赖于当前的包名

Python:Django3.1 框架学习笔记_第9张图片

当修改了包名后,由于之前生成的表已经存在,导致在数据库中寻找对应的表会报错

解决方法:通过在模型类中创建猿类Meta ,在元类中定义属性db_table指定表名

class Meta:
	db_table = '表名'

例:

class AreaInfo(models.Model):
    """自关联全国地区信息"""
    area_name = models.CharField(max_length=100)

    # 设置自关联外键,null表示该字段在数据库中可以为空,blank表示后台管理页面中该字段可以为空白,必须指明on_delete
    area_parent = models.ForeignKey('AreaInfo', null=True, blank=True, on_delete=models.CASCADE, db_constraint=False)

    class Meta:
        db_table = 'areainfo'

Python:Django3.1 框架学习笔记_第10张图片

·

6.通过模型类操作数据表

进入项目shell命令

$ python3 manage.py shell

● 首先导入models包下的模型类

● 创建模型类的对象

Python:Django3.1 框架学习笔记_第11张图片
● 可以通过对象增加实例属性,可以查看实例属性,可以修改实例属性,也可以删除实例属性,例如:

>> from booktest.models import BookInfo
>>> b = BookInfo()
>>> b.btitle = '一本书'
>>> from datetime import date
>>> b.bpub_date = date(1999,1,1)
>>> b.save()

● 最后该实例对象调用save()方法可以将添加的实例属性进行提交,更改数据库中的内容

·

● 当需要得到或者查询数据库里的内容时,通过 模型类名.objects.get(条件) 可以返回一个对象,透过该对象也可以得到这条信息里面相应的值,也可以对表的内容进行修改(修改后需要调用save()方法才能实现),或者删除该条信息。

>>> b2 = BookInfo.objects.get(id=1)
>>> b2.btitle
'一本书'
>>> b2.bpub_date
datetime.datetime(1999, 1, 1, 0, 0, tzinfo=<UTC>)
>>> b2.btitle = '两本书'
>>> b2.save()
>>> b2.delete()
(1, {'booktest.BookInfo': 1})

·

创建一对多关系—外键的使用(这里再定义一个英雄模型类,类中hbook为BookInfo的外键)

Python:Django3.1 框架学习笔记_第12张图片

例:图书类-英雄类

xx = models.ForeignKey() 定义在多的类中。

class HeroInfo(models.Model):
    """英雄类"""

    hname = models.CharField(max_length=20)

    # 英雄性别,默认False为男性
    hgender = models.BooleanField(default=False)
    hcomment = models.CharField(max_length=20)

    # on_delete=models.CASCADE,级联删除,删除主表的数据时从表数据也删除
    hbook = models.ForeignKey('BookInfo', on_delete=models.CASCADE)

shell

>>> h2 = HeroInfo(
... hname = '小红',
... hgender = True,
... hcomment = '撞击',
... hbook = b1)
>>> h2.save()
>>> h2.hbook_id
1
>>> h2.hbook
<BookInfo: BookInfo object (1)>
>>> h2.hbook.btitle
'遮天'
>>> h2.hbook.bpub_date
datetime.datetime(1998, 1, 1, 0, 0, tzinfo=<UTC>)

程序会自动为外键生成一个id, h2.book_id 保存的是h2外键关联BookInfo类的id
这里 h2.hbook 是一个对象。指向的是BookInfo类中当id=1(即BookInfo.objects.get(id=1)

·

>>> b1 = BookInfo.objects.get(id=1)
>>> b1.heroinfo_set.all()
<QuerySet [<HeroInfo: HeroInfo object (1)>, <HeroInfo: HeroInfo object (2)>]>

当指明了外键后,BookInfo类中通过对象可以知道每本书对应着哪些英雄,通过 b1.heroinfo_set.all() 可以显示出所关联该对象的英雄对象,这就是一对多
·

创建多对多关系

例:新闻类-新闻类型类 体育新闻 国际新闻

xx = models.ManyToManyField() 定义在哪个类中都可以。

·

创建一对一关系

例:员工基本信息类-员工详细信息类. 员工工号

xx = models.OneToOneField() 定义在哪个类中都可以。

·

7.关于Django 管理页面

Python:Django3.1 框架学习笔记_第13张图片

·

本地化

语言时区 本地化

修改setting.py文件

Python:Django3.1 框架学习笔记_第14张图片

·

创建一个管理员账号

$ python3 manage.py createsuperuser

键入你想要使用的用户名,然后按下回车键:

Username: admin

然后提示你输入想要使用的邮件地址:

Email address: [email protected]

最后一步是输入密码。你会被要求输入两次密码,第二次的目的是为了确认第一次输入的确实是你想要的密码。

Password: **********
Password (again): *********
Superuser created
successfully.

·

要想在后台管理界面中出现模型类,需要将应用程序里的模型类注册到admin.py中,告诉管理员该模型类对象需要一个后台接口

Python:Django3.1 框架学习笔记_第15张图片

·

启动开发服务器

$ python3 manage.py runserver

打开浏览器,输入 "127.0.0.1:8000/admin/ ",可以看见管理员登陆界面

通过管理员页面,可以增加删除用户也可以体验快捷的数据操作

·

将后台管理页面中的数据表以标题的形式展现

Python:Django3.1 框架学习笔记_第16张图片

解决方法:

通过在models.py模块中,为每个模型类添加魔法方法 __str__(self),使得 str(类的实例对象) 返回一个自定义的内容。

如图:

Python:Django3.1 框架学习笔记_第17张图片
-------------------------------------------------------------------------------------------------------------------------------------------------------

Python:Django3.1 框架学习笔记_第18张图片

·

自定义后台模型管理类

在后台管理页面中,可以在 admin.py 中自定义模型类展示的形式

代码:
booktest/admin.py

from django.contrib import admin

from .models import BookInfo, HeroInfo


# Register your models here.

class BookInfoAdmin(admin.ModelAdmin):
    """图书模型管理类"""
    list_display = ['id', 'btitle', 'bpub_date']


class HeroInfoAdmin(admin.ModelAdmin):
    """英雄模型管理类"""
    list_display = ['id', 'hname', 'hgender', 'hcomment', 'hbook']


admin.site.register(BookInfo, BookInfoAdmin)
admin.site.register(HeroInfo)

-------------------------------------------------------------------------------------------------------------------------------------------------------

Python:Django3.1 框架学习笔记_第19张图片

·

·

8.将默认数据库sqlite3换成MySQL

首先将setting.py中默认的数据库换成MySQL

Python:Django3.1 框架学习笔记_第20张图片

通过MySQL测试链接成功后,将模型类文件进行迁移 (迁移文件在之前已经生成过了)

$ python3 manage.py migrate

如果出现以下错误,则说明系统中没有安装mysqlclient

(vtpy01) user@ubuntu:~/桌面/python/Django_study/test1$ python3 manage.py migrate
Traceback (most recent call last):
  File "/home/user/.virtualenvs/vtpy01/lib/python3.8/site-packages/django/db/backends/mysql/base.py", line 15, in <module>
    import MySQLdb as Database
ModuleNotFoundError: No module named 'MySQLdb'

The above exception was the direct cause of the following exception:
.
.
.
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
Did you install mysqlclient?

mysqlclient对于python来说需要一个具体位置的配置信息不好用

这里安装pymysql,用pymysql可以伪装成MySQclient

(vtpy01) user@ubuntu:~/桌面/python/Django_study/test1$ pip3 install pymysql
Collecting pymysql
  Downloading PyMySQL-0.10.1-py2.py3-none-any.whl (47 kB)
     |████████████████████████████████| 47 kB 36 kB/s 
Installing collected packages: pymysql
Successfully installed pymysql-0.10.1

安装好后,需要在程序运行前让pymysql伪装成MySQclient

Python:Django3.1 框架学习笔记_第21张图片

再次执行迁移文件迁移命令,成功

(vtpy01) user@ubuntu:~/桌面/python/Django_study/test1$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, booktest, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
.
.
.

·

·

9.视图文件的使用

首先在应用程序的视图文件view.py中添加一个简单的视图

test1/booktest/view.py

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


# Create your views here.
def index(request):
    return HttpResponse("Hello, my first Django on index")

要调用视图,我们需要将其映射到一个URL,因此在应用程序包(app包)下要创建一个urls.py文件,当作URLconf(url配置文件)。

test1/booktest/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('index', views.index, name='index'),
    
]

path()函数传递了四个参数,两个是必需的:路由和视图,两个是可选的:kwargs 和 name.

● path() argument: route

route 是一个包含 URL 模式的字符串。在处理请求时,Django 从 urlpatterns 中的第一个模式开始,沿着列表向下移动,将所请求的 URL 与每个模式进行比较,直到找到一个匹配的。
模式不搜索 GET 和 POST 参数或域名。例如,在对https://www.example.com/myapp/的请求中,URLconf 将查找 myapp/。在请求https://www.example.com/myapp/?页面 =3 时,URLconf 也会查找 myapp/。

● path() argument: view

当 Django 找到匹配的模式时,它调用指定的视图函数,第一个参数是 HttpRequest 对象,从路由中“捕获”的任何值都是关键字参数。

● path() argument: kwargs

可以在字典中将任意关键字参数传递给目标视图。

● path() argument: name

name 表示的是route匹配到的URL的一个别名。通过命名 URL,您可以从 Django 的其他地方明确地引用它,特别是在模板中。这个强大的特性允许您在只修改单个文件的同时对项目的 URL 模式进行全局更改。

利用path()和re_path(),在url中取特定的不固定页面

path('< int(str,):形参 >') or re_path(r'^正则表达式')

path函数中捕获url中的参数需要用到尖括号<> 指定尖括号中的值类型比如< str:link>这个转换器还有许多类型比如:

int 匹配0和正整数

str 匹配任何空字符串但不包括/

slug 可理解为注释 匹配任何ascii码包括连接线和下划线

uuid 匹配一个uuid对象(该对象必须包括破折号—,所有字母必须小写)

取出来的的值会当作实参传入到path()方法的第二个参数: 引用视图模块里对应的方法

re_path函数中捕获url中的参数需要用到正则表达式里的分组括号,按照第一个括号分别作为参数传入views里相对应的方法中。

例如,这里会把 (\d+) 里的值当作参数传入:

from django.urls import re_path
re_path(r'^delete/(\d+)$', views.delete, name='delete')

·

·

随后将主项目的URLconf(test1/urls.py)指向应用里的urls模块

test1/urls.py

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

# 项目的urls文件
urlpatterns = [
    path('admin/', admin.site.urls),  # 配置项目
    path('booktest/', include('booktest.urls')),
    
]

include()函数允许引用其他 URLconf。每当 Django 遇到 include()时,它都会截断匹配到该点的 URL 的任何部分,并将剩余的字符串发送到包含的 URLconf 中以进行进一步处理。

·

python3 manage.py runserver运行后

Python:Django3.1 框架学习笔记_第22张图片

·

关闭浏览器页面的DEBUG显示以及错误视图(404和500)

在新建的Django项目中,当访问的url或服务器出错时,默认浏览器会显示出DEBUG页面

控制这一显示的选项在 setting.py

在这里插入图片描述

将DEBUG改为False则可关闭这一显示,并且必须在ALLOWED_HOST中填入允许访问的地址,允许所有地址这里填入 ALLOWED_HOST = ['*']
在这里插入图片描述
这里显示的页面是Django提供的404错误页面
Python:Django3.1 框架学习笔记_第23张图片

404错误显示:当页面显示404错误是指找不到访问的资源,在框架中一般是url没有配置或者url配置错误

500错误显示:当页面显示500错误时,是表示服务器端出现错误,在框架中一般是视图文件或者模板文件出现了错误

·

·

自定义错误视图

在项目根目录下的模板目录(见下一节模板文件的使用)下创建404.html500.html文件

● 这里以404.html为例,当访问的资源找不到时,Django会自动调用模板目录里的404.html,如果没有自定义该文件时,会返回Django自带的404错误信息

● 这里request_path 是Django中的魔法属性,表示请求的url路径

Python:Django3.1 框架学习笔记_第24张图片
Python:Django3.1 框架学习笔记_第25张图片

·

·

·

关于返回对象request的属性:(属性基本都是只读的,无法进行修改,除encoding和session)

path:一个字符串,表示请求页面的完整路径,不包含域名参数部分

META:可通过 request.META['REMOTE_ADDR'] 来获取浏览器端的ip地址

method:一个字符串,表示请求的HTTP方法,常用值包括:‘GET’,‘POST’。

encoding:一个字符串,表示提交的数据的编码方式。
。如果为None则表示使用浏览器的默认设置,一般为utf-8.
。该属性为可写,可通过修改它,来修改访问表单数据使用的编码,接下来对属性的任何访问都将使用新的encoding值

GET:QueryDict类型对象,类似于字典,包含get请求方式的所有参数。

POST:QueryDict类型对象,类似于字典,包含post请求方式的所有参数。

FILES:一个类似于字典对象,包含所有的上传文件。

COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串。

session:一个既可以读又可以写的类似于字典的对象,表示当前的会话,只有当Django启用会话的支持时才可使用

·

·

关于返回对象request的请求提交参数的方法(GET,POST)

request是一个HttpRequest对象

当进行登录提交的时候通过request对象根据提交的方式可以获得需要的提交内容:
这里提交的方式有两种(GET,POST)

GET: 提交的参数在url中
POST: 提交的参数在请求头中。在对数据安全性要求比较高的时候用POST。

·

在框架中通过request对象获取页面提交的参数内容:

request.POST.get('XXX')

request.GET.get('XXX')

request.POST/GET 返回的是 QueryDict 类型,QueryDict类型是一种类似字典(key-value)的类型,与字典不同的是在QueryDict中可以一次或多次保存多个同名key的值,不会被覆盖,并且通过 getlist(‘key’) 方法可以将该键保存的多个数值全部显示出来,通过 get(‘key’) 方法可以获取对应的value值,当该key有多个值时, get(‘key’) 方法会获取最后一个或者最后一次保存的值。

例:

templates/booktest/login_page.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>登陆页面</title>
</head>
<body>
<form method="post" action="/login_check">
    用户名:<input type="text" name="nameuser"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="submit" value="登录">



</form>

</body>
</html>

booktest/views.py

def login(request):
	"""页面显示"""
	
    return render(request, 'booktest/login_page.html')

def login_check(request):
	"""登录按钮点击效验"""
	
	# 通过request对象获取页面提交的参数内容
    nameuser = request.POST.get('nameuser')
    password = request.POST.get('password')

    if nameuser == 'admin' and password == '123':
        return redirect('/books')
    else:
        return redirect('/login')

·

10. 静态文件

在网页使用的css文件,js文件和图片叫做静态文件。

● 在项目根目录下创建 static目录
Python:Django3.1 框架学习笔记_第26张图片

·

● 配置静态文件所在的物理目录

settings.py
Python:Django3.1 框架学习笔记_第27张图片

STATIC_URL 设置访问静态文件对应的url。
STATICFILES_DIRS 设置静态文件所在的物理目录。

·

● 当STATIC_URL改变时,模板文件里对应的对静态文件的链接也必须更改为相应的url,否则会找不到该文件。

对于此情况,可以在模板文件中动态生成静态文件的链接。

1)在模板文件中加载static----> {% load static %}

2)动态获取STATIC_URL,拼接静态文件路径 ----->

代码实例:

show_image.html


{% load static %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>显示图片title>
head>
<body>

<img src="/static/image/1.jpg"><br/>

动态获取STATIC_URL,拼接静态文件路径:<br/>
<img src="{% static 'image/1.jpg' %}">
body>
html>

·

11. Ajax请求

Ajax:异步的JavaScript

在不重新加载页面的情况下,对页面进行局部的刷新

$.ajax({
	'url':请求地址,
	'type':请求方式,
	'dataType':预期返回的数据格式(一般是json格式),
	'data':参数
	}).success(function(回调的数据){
	//Ajax请求执行完成之后执行的回调函数
	})
	

当浏览器发起Ajax请求给后端,后端在views文件中进行处理,并返回 return JsonResponse(回调的数据),将json数据返回给浏览器,浏览器执行success()回调函数。

注:当Ajax请求出现错误时,只能通过浏览器查看错误信息

·

关于Ajax同步与异步

异步:不等待回调函数的执行完成,直接运行后续代码
同步:等待回调函数执行完成后才继续运行后面的代码

$.ajax({
	'url':请求地址,
	'type':请求方式,
	'dataType':预期返回的数据格式(一般是json格式),
	'data':参数,
	'async':false
	}).success(function(回调的数据){
	//Ajax请求执行完成之后执行的回调函数
	})
	

·

Ajax登录案例代码

用表单(< form >)完成登录案例

login_page.html


<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>登陆页面title>
head>
<body>
<form method="post" action="/login_check">
    用户名:<input type="text" name="nameuser"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="submit" value="登录">
form>
body>
html>

views.py

def login(request):
    return render(request, 'booktest/login_page.html')


def login_check(request):
    nameuser = request.POST.get('nameuser')
    password = request.POST.get('password')
    print(request.path)
    try:
        user = UserInfo.objects.get(username=nameuser)
    except:
        print('aaaaaaaa')
        return redirect('/login')
    else:
        if user.password == int(password):
            return redirect('/books')
        else:
            print(user.password)

            return redirect('/login')

·

用Ajax完成登录案例

login_ajax.html


<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>ajax登陆页面title>
    <script src="/static/js/jquery-1.12.4.min.js">script>
    <script>
        $(function(){
            $('#btnLogin').click(function () {
                // 获取用户名和密码
                nameuser = $('#nameuser').val()
                passqord = $('#password').val()
                // 发起post ajax 请求
                $.ajax({
                    'url':'login_ajax_check',
                    'type':'post',
                    'data':{'username':nameuser, 'password':passqord},
                    'datatype':'json'
                }).success(function (data) {
                    // 登录成功{'res':1}
                    // 登录失败{'res':0}
                    if (data.res === 0){
                        $('#errmsg').show().html('用户名输入错误')
                    }
                    else if(data.res === 2){
                        $('#errmsg').show().html('密码输入错误')
                    }
                    else {
                        // 跳转到图书界面
                        location.href = '/books'
                    }
                })
            })
        })
    script>
    <style>
        #errmsg{
            display: none;
            color: red;
        }
    style>
head>
<body>
<div>
    用户名:<input type="text" id="nameuser"><br/>
    密码:<input type="password" id="password"><br/>
    <input type="button" id="btnLogin" value="登录">
    <div id="errmsg">div>
div>
body>
html>

views.py

def login_ajax(request):
    return render(request, 'booktest/login_ajax.html')


def login_ajax_check(request):
    # 获取用户名和密码
    username = request.POST.get('username')
    password = request.POST.get('password')

    # 进行效验,返回json数据
    print(username)
    print(password)
    try:
        u1 = UserInfo.objects.get(username=username)
    except:
        print('aaaaa')
        return JsonResponse({'res': 0})

    else:
        if u1.password == int(password):
            print('bbbbb')
            return JsonResponse({'res': 1})
        else:
            print('cccc')
            return JsonResponse({'res': 2})

·

登录效验失败的解决方法(csrf防护及防御原理)

当进行效验的时候会出现下面的界面,是因为在setting.py里的MIDDLEWARE[ ]中的'django.middleware.csrf.CsrfViewMiddleware'这一选项造成

注:'django.middleware.csrf.CsrfViewMiddleware'在Django中默认启用了csrf防护,防止出现csrf伪造攻击网站,只针对post提交

Python:Django3.1 框架学习笔记_第28张图片
解决方法是:

在所有的post提交下面增加一个模板标签

{% csrf_token %}

防御原理:

1)渲染模板文件时在页面生成一个名字叫做csrfmiddlewaretoken的隐藏域。
2)服务器交给浏览器保存一个名字为 csrftoken 的 cookie 信息。
3)提交表单时,两个值都会发给服务器,服务器进行比对,如果一样,则csrf验证通过,否则失败。

·

.

12. 状态保持

http协议是无状态的,即下一次去访问一个页面时并不知道上一次这个页面做了什么。

在web中记录信息的两种方式:cookiesession

·

Cookie

是以服务器生成,存储在浏览器端的一小段文本信息

特点:

1)以键值对方式进行存储。

2)通过浏览器访问一个网站时,会将浏览器存储的跟网站相关的所有cookie信息发送给该网站的服务器。 request.COOKIES

3)cookie 是基于域名安全的。

4) cookie 是有过期时间的,如果不指定,默认关闭浏览器后 cookie 就会过期。

Python:Django3.1 框架学习笔记_第29张图片

代码实例:

views.py

from django.http import HttpResponse


def set_cookie(request):
	'''设置cookie信息'''

	# 创建一个HttpResponse对象
	response = HttpResponse('设置cookie')
	# 设置一条cookie信息,设定过期时间为14天后
	response.set_cookie('num', 1, max_age=14*24*3600)
	return response

Python:Django3.1 框架学习笔记_第30张图片

`

views.py

from django.http import HttpResponse

def get_cookie(resquest):
	'''获得cookie值'''
	
	# request属性COOKIES字典中保存了所有的cookie键值对,通过COOKIES取出对应的值
	num = request.COOKIES['num']
	return HttpResponse(num)

Python:Django3.1 框架学习笔记_第31张图片

·

·

登录案例–通过cookie记住用户名和密码

views.py

def login_ajax(request):
    if 'username' in request.COOKIES:
        username = request.COOKIES['username']
    else:
        username = ''
    if 'password' in request:
        password = request.COOKIES['password']
    else:
        password = ''

    return render(request, 'booktest/login_ajax.html', {'username': username, 'password': password})


def login_ajax_check(request):
    # 获取用户名和密码
    username = request.POST.get('username')
    password = request.POST.get('password')

    # 获取是否记住用户名和密码的选项勾选状态,为None表示没有勾选,为on表示勾选
    remember = request.POST.get('remember')

    # 进行效验,返回json数据
    try:
        # 从数据库中获取姓名为username的对象
        u1 = UserInfo.objects.get(username=username)
    except:
        return JsonResponse({'res': 0})

    else:
        if u1.password == int(password):
            response = JsonResponse({'res': 1})
            # 当数据库中存在该用户名和密码时设置cookie值,设置过期时间为一周
            response.set_cookie('username', username, max_age=7*24*3600)
            response.set_cookie('password', password, max_age=7*24*3600)
            return response
        else:
            return JsonResponse({'res': 2})

·

login_ajax.html


<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>ajax登陆页面title>
    <script src="/static/js/jquery-1.12.4.min.js">script>
    <script>
        $(function(){
            $('#btnLogin').click(function () {
                // 获取用户名和密码
                nameuser = $('#nameuser').val()
                passqord = $('#password').val()

                // 发起post ajax 请求
                $.ajax({
                    'url':'login_ajax_check',
                    'type':'post',
                    'data':{'username':nameuser, 'password':passqord},
                    'datatype':'json'
                }).success(function (data) {
                    // 登录成功{'res':1}
                    // 登录失败{'res':0}

                    if (data.res === 0){
                        $('#errmsg').show().html('用户名输入错误')

                    }
                    else if(data.res === 2){

                        $('#errmsg').show().html('密码输入错误')
                    }
                    else {
                        // 跳转到图书界面
                        location.href = '/books'
                    }
                })
            })
        })
    script>
    <style>
        #errmsg{
            display: none;
            color: red;
        }
    style>
head>
<body>
<div>
    用户名:<input type="text" id="nameuser" value="{{ username }}"><br/>
    密码:<input type="password" id="password" value="{{ password }}"><br/>
    <input type="checkbox" name="remember">记住用户名<br/>
    <input type="button" id="btnLogin" value="登录">
    <div id="errmsg">div>
div>
body>
html>

实验结果:

Python:Django3.1 框架学习笔记_第32张图片
·

·

Python:Django3.1 框架学习笔记_第33张图片

·

·

·

session

session存储在服务器端

特点:

1)session 是以键值对进行存储的

2)session 依赖于 cookie。唯一的 标识码保存在 sessionid cookie

3)session 也有过期时间,如果不指定,默认两周就会过期

设置session:request.session[‘username’] = ‘xxx’
获取session:request.session[‘username’]

Python:Django3.1 框架学习笔记_第34张图片
·

通过HttpRequest对象的session属性进行读写操作

1)以键值对的格式写入session

request.session[‘键’] = 值

2)根据键读取值

request.session.get(‘键’, 默认值)

3)清除所有session,在存储中(数据库中django自建的session表)删除值部分,键(唯一标识码)保留

request.session.clear()

4)清楚session数据,在存储中删除session的整条数据

request.session.flush()

5)删除session中的指定键的值,在存储中只删除某个键对应的值,键保留

del request.session[‘键’]

6)设置会话的超过时间,如果没有指定过期时间则两个星期后过期

request.session.set_expiry(value)

● 如果value是一个整数,会话的session_id cookie将在value秒没有活动后过期。
● 如果value为0,那么用户会话的session_id cookie将在用户的浏览器关闭时过期。
● 如果value为None,那么会话的session_id cookie两周之后过期。

·

代码实例

views.py

from django.http import HttpResponse

def set_session(request):
	request.session['name'] = 'name'
	request.session['age'] = 18
	return HttpResponse('设置session')
	

Python:Django3.1 框架学习笔记_第35张图片

`

from django.http import HttpResponse

def get_session(request):
	name = request.session['name']
	age = request.session['age']
	return HttpResponse(name+':'+str(age))
	

Python:Django3.1 框架学习笔记_第36张图片

`

`

登录案例–记住用户登录状态,下次访问直接登录跳转不必输入用户和密码

代码实例:

views.py

def login_ajax(request):
    # 当服务器session表中含有键isLogin时,直接转到图书界面
    if request.session.has_key('isLogin'):
        return render(request, 'booktest/books_display.html')
    else:
        if 'username' in request.COOKIES:
            username = request.COOKIES['username']
        else:
            username = ''
        if 'password' in request:
            password = request.COOKIES['password']
        else:
            password = ''

        return render(request, 'booktest/login_ajax.html', {'username': username, 'password': password})


def login_ajax_check(request):
    # 获取用户名和密码
    username = request.POST.get('username')
    password = request.POST.get('password')

    # 获取是否记住用户名和密码的选项勾选状态,为None表示没有勾选,为on表示勾选
    remember = request.POST.get('remember')

    # 进行效验,返回json数据
    try:
        # 从数据库中获取姓名为username的对象
        u1 = UserInfo.objects.get(username=username)
    except:
        return JsonResponse({'res': 0})

    else:
        if u1.password == int(password):
            response = JsonResponse({'res': 1})
            # 当数据库中存在该用户名和密码时设置cookie值,设置过期时间为一周
            response.set_cookie('username', username, max_age=7 * 24 * 3600)
            response.set_cookie('password', password, max_age=7 * 24 * 3600)

            # 利用session,设置用户已登录
            request.session['isLogin'] = True
            return response
        else:
            return JsonResponse({'res': 2})

login_ajax.html


<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>ajax登陆页面title>
    <script src="/static/js/jquery-1.12.4.min.js">script>
    <script>
        $(function(){
            $('#btnLogin').click(function () {
                // 获取用户名和密码
                nameuser = $('#nameuser').val()
                passqord = $('#password').val()

                // 发起post ajax 请求
                $.ajax({
                    'url':'login_ajax_check',
                    'type':'post',
                    'data':{'username':nameuser, 'password':passqord},
                    'datatype':'json'
                }).success(function (data) {
                    // 登录成功{'res':1}
                    // 登录失败{'res':0}

                    if (data.res === 0){
                        $('#errmsg').show().html('用户名输入错误')

                    }
                    else if(data.res === 2){

                        $('#errmsg').show().html('密码输入错误')
                    }
                    else {
                        // 跳转到图书界面
                        location.href = '/books'
                    }
                })
            })
        })
    script>
    <style>
        #errmsg{
            display: none;
            color: red;
        }
    style>
head>
<body>
<div>
    用户名:<input type="text" id="nameuser" value="{{ username }}"><br/>
    密码:<input type="password" id="password" value="{{ password }}"><br/>
    <input type="checkbox" name="remember">记住用户名<br/>
    <input type="button" id="btnLogin" value="登录">
    <div id="errmsg">div>
div>
body>
html>

Python:Django3.1 框架学习笔记_第37张图片

·

·

cookie和session的区别和应用场景

cookie记住用户名。 安全性要求不高。

session涉及到安全性要求比较高的数据。银行卡账户,密码,登陆状态等。

·

cookie保存在客户端
session保存在服务器端

·

cookie的值会直接显示出来
session的值会经过base64编码后保存

·

cookie在Django框架中通过HttpResponse的对象进行设置,获取
session在Django框架中通过request对象进行设置,获取

.

.

13.模板

模板语言简称为DTL(Django Template Language)

13.1 模板语言

13.1.1 模板变量及解析顺序

模板变量名由数字,字母,下划线和点组成,不能以下划线开头使用模板变量:{{ 模板变量名 }}

解析顺序:

例如: {{ book.btitle }}

1)首先把 book 当成一个字典,把 btitle 当成键名,进行取值 book['btitle’]
2)把book当成一个对象,把 btitle当成属性,进行取值book.btitle
3)把book 当成一个对象,把 btitle 当成对象的方法,进行取值book.btitle

例如: {{ book.0 }}

1)首先把book当成一个字典,把0当成键名,进行取值book[0]
2)把book当成一个列表,把0当成下标,进行取值 book[0]

如果解析失败,则产生内容时用空字符串填充模板变量。

使用模板变量时,“. ”前面的可能是一个字典,可能是一个对象,也可能是一个列表。

·

13.1.2 模板标签

格式:{% 代码段 %}

for 循环:

{% for i in 列表 %}
     xxx   // 列表不为空时执行
{% empty %}
     xxx   // 列表为空时执行
{% endfor %}

可以通过{{ forloop.counter }}得到for循环遍历到了第几次。

if语句:

{% if条件 %}
{% elif条件 %}
{% else %}
{% endif %}

关系比较操作符:> , < , >= , == , !=
注:进行比较操作时,比较操作符两边必须有空格。

逻辑运算: not and or

代码实例:

book.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板标签title>
    <style>
        .yellow {
            background-color: yellow;
        }
    style>
head>
<body>

{% for i in  books  %}
    {% if i.id <= 1 %}
        <li class="yellow">{{ i.btitle }}li>
    {% endif %}
{% endfor %}
body>
html>

views.py

def books_play(request):
    book_all = Book.objects.all()
    return render(request, 'booktest/book.html', {'books': book_all})

实验结果:
Python:Django3.1 框架学习笔记_第38张图片

·

13.1.3 模板过滤器

过滤器用于对模板变量进行操作

过滤器本质是python函数

date:改变日期的显示格式

length:求长度。字符串,列表,元组,字典长度

default:设置模板变量的默认值

格式:模板变量 | 过滤器: 参数

具体见
Django文档–关于模板标签和过滤器

·

代码实例:

books_display.html


<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>显示图书信息title>
head>
<h3>图书信息:h3>
<a href="/create">新增a>
<body>
{% for book in books %}

        <li><a href="/books/{{ book.id }}">{{ book.btitle }}a>---{{ book.bpub_date|date:'Y年-m月-d日' }} // 对日期的显示增加过滤器
            <a href="/delete/{{ book.id }}">删除a>li>
{% endfor %}
<br/>
default过滤器:<br/>
{{ content|default:'默认值' }}
body>
html>

views.py

def books_display(request):
    books = BookInfo.objects.all()

    return render(request, 'booktest/books_display.html', {'books': books})

实验结果:
在这里插入图片描述

·

自定义过滤器

1)首先,在app路径下创建 templatetags 的python package

2)在templatetags目录中创建自定义的python文件

3)导入包(from django.template import Library

4)创建LIbrary()对象

5)创建功能函数并进行装饰器装饰

6)在模板文件中加载自定义的python文件

7)增加过滤器

注:自定义的过滤器函数,至少有一个参数,最多两个参数

代码实例:
booktest/templatetags/filter_test.py

# 自定义过滤器
# 过滤器实质上是python函数

from django.template import Library

# 创建一个Library类的对象
register = Library()


@register.filter
def mod(num):
    '''判断num是否为偶数'''

    return num % 2 == 0


# 自定义的过滤器函数,至少有一个参数,最多两个
@register.filter()
def mod_val(num, val):
    '''判断num是否能被val整除'''

    return num % val == 0

books_display.html


<html lang="en" xmlns="http://www.w3.org/1999/html">
{% load filter_test %}
<head>
    <meta charset="UTF-8">
    <title>显示图书信息title>
head>
<h3>图书信息:h3>
<a href="/create">新增a>
<body>
{% for book in books %}
        <li>{{ book.id }}--{{ book.id|mod }}---<a href="/books/{{ book.id }}">{{ book.btitle }}a>
            ---{{ book.bpub_date|date:'Y年-m月-d日' }}--{{ book.id|mod_val:3 }}
            <a href="/delete/{{ book.id }}">删除a>li>
{% endfor %}
<br/>
default过滤器:<br/>
{{ content|default:'默认值' }}
body>
html>

实验结果:
Python:Django3.1 框架学习笔记_第39张图片

·

13.1.4模板注释

单行注释

{# 注释内容 #}

多行注释:

{% comment %}
注释内容
{% endcomment %}

● 模板注释与html注释的区别

模板注释 通过浏览器检查网页源代码不会显示
html注释 通过浏览器检查网页源代码会显示出来

·

13.1.5 模板继承

在子模版中需要继承父模板时

{% extends '父模板路径' %}

● 子模版继承父模板后会继承父模板所有模板内容,并且无法直接增加内容,标题也和父模板一样

● 在父模板中增加预留块,在子模版中可通过对预留块的改写增加内容

● 在子模版的预留块中可通过 {{ block.super }} 继承父模板中该预留块的内容

● 对父模板的标题增加预留块,在子模版可以通过该预留块改写子模版的标题

Python:Django3.1 框架学习笔记_第40张图片

·

实例代码:

parentTemplate.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}父模板{% endblock title %}title>
head>
<body>
<h1>这是父模板h1>

{% block b1 %}
    <h3>父模块b1信息h3>
{% endblock b1 %}

{% block b2 %}
{% endblock b2 %}
body>
html>

subTemplate.html

{% extends 'booktest/parentTemplate.html' %}
{% block title %}子模版{% endblock title %}
{% block b1 %}

{{ block.super }}
<h3>这是子模块b1的内容h3>

{% endblock b1 %}

{% block b2 %}
<h3>这是子模块b2的内容h3>
{% endblock b2 %}

实验结果:
Python:Django3.1 框架学习笔记_第41张图片

·

13.1.6 html转义

在模板上下文中的html标签默认是会被转义的

小于号 < 转换为 <
大于号 > 转换为 >
单引号 ‘ 转换为 '
双引号 " 转换为 "
与符号 & 转换为 &

要关闭模板上下文的转义,有两种方法:

过滤器

{{ 模板变量|safe }}

● 模板标签

{% autoescape off %}
模板语言代码
{% endautoescape %}

代码实例:

views.py

def escape_test(request):
    return render(request, 'booktest/escape_test.html', {'content': '

hello

'
})

escape_test.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转义title>
head>
<body>
未进行转义时:<br/>
{{ content }}
<br/>
<br/>
用过滤器进行转义:
{{ content| safe }}
<br/>
用模板标签进行转义:
{% autoescape off %}
{{ content }}
{{ content }}
{% endautoescape %}
body>
html>

实验结果:
Python:Django3.1 框架学习笔记_第42张图片

● 在模板硬编码中的字符串默认不会经过转义,如果需要转义,则需要手动进行转义

硬编码指的是在模板文件中固定死的静态代码

代码实例:

escape_test.html

模板硬编码中的字符串默认不会经过转义:<br/>
{{ tag|default:'<h1>helloh1>' }}<br/>
<br/>
手动进行转义:<br/>
{{ tag|default:'<h1>hello</h1>' }}
body>
html>

实验结果:
Python:Django3.1 框架学习笔记_第43张图片

·

·

13.2 模板目录(templates)有两种创建路径:

1)在项目根目录中创建templates目录,该目录下存放模板文件

创建好后,在setting.py 文件中,配置一下模板文件的目录

Python:Django3.1 框架学习笔记_第44张图片

setting.py文件中有一个变量 BASE_DIR 表示这个项目的绝对路径,在本实验环境下为“/home/user/桌面/python/Django_test/test1

Python:Django3.1 框架学习笔记_第45张图片

则在模板路径中应该填入

os.path.join(BASE_DIR, ‘templates’) (路径相加需要用到os.path.join()方法)

Python:Django3.1 框架学习笔记_第46张图片

2)在应用目录下创建templates目录,该目录下存放模板文件

在应用目录下创建后无需填写setting.py文件中的TEMPLATES的‘DIRS’,但必须让‘APP_DIRS'设置为True

注:当两种模板目录的存放方式都写了时,Django框架寻找模板文件时优先在项目根目录下寻找templates目录,如果没找到再去应用目录下寻找templates目录,当都没找到的话就会报出错误TemplateDoesNotExist at xxx/xxx
·

13.3 模板文件加载顺序

当服务器url正确时,服务器寻找相应的模板文件的顺序为下面红框中内容
Python:Django3.1 框架学习笔记_第47张图片

·

·

在templates目录下创建与应用同名的目录,比如这里我的应用名是booktest,我就在templates目录下创建一个booktest目录,在每个应用目录下存放属于该应用的模板文件

·

通过render方法调用模板文件,获取内容,进行模板渲染(将传入的值替换模板文件中相应的值),最后返回给浏览器

Python:Django3.1 框架学习笔记_第48张图片

·

·

14.页面重定向(from django.shortcuts import redirect)

当在浏览器上点击了一个链接,但是想在当前页面中执行功能不进行跳转,则可以使用页面重定向

页面重定向: 服务器不返回页面,而是告诉浏览器再去请求其他的url地址。

重定向流程:

点击链接–>浏览器发送请求访问相应的url地址–>框架执行相应功能返回给浏览器–>并且告诉浏览器去访问想跳转的url地址–>浏览器访问该url地址

使用方法:
booktest/view.py

# from django.http import HttpResponseRedirect
from django.shortcuts import  redirect # 导入重定向函数

def 执行功能(request):
	pass
	# return HttpResponseRedirect('要跳转的url页面(比如:'/index')')
	return redirect('要跳转的url页面(比如:'/index')')

·

·

15. 中间件

中间件是Django框架给开发者预留的函数接口,使得可以干预请求和应答的过程

15.1 使用中间件

1)在应用路径下新建middleware.py文件

2)自定义中间件类,导入from django.utils.deprecation import MiddlewareMixin,中间件类必须继承MiddlewareMixin

3)在中间件类中定义中间件预留函数

__init __:服务器响应第一个请求的时候调用

process_request:是在产生request对象,进行url匹配之前调用。

process_view:是url匹配之后,调用视图函数之前调用。

process_response:视图函数调用之后,内容返回给浏览器之前调用。

process_exception:视图函数出现异常,会调用这个函数。

注:如果注册的多个中间件类中包含process_exception函数的时候,调用的顺序和注册的顺序是相反的

更多中间类,查看官网文档

·
例:
Python:Django3.1 框架学习笔记_第49张图片
4)在settings.py文件里的 MIDDLEWARE[ ] 中注册中间件类

Python:Django3.1 框架学习笔记_第50张图片

·

代码实例:

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

class TestMiddleware(MiddlewareMixin):
    """中间件类"""

    def __init__(self, get_response):
        '''服务器每次开启时,接收第一个请求时调用。__init__()参数中必须要有get_response'''
        self.get_response = get_response
        print("__init__")

    def process_request(self, request):
        '''产生request对象后,与url匹配之前调用'''
        print('___process_request____')

    def process_view(self, request, view_func, *view_args, **view_kwargs):
        '''与url匹配之后,在视图函数调用之前调用'''

        print('___process_view___')

    def process_response(self, request, response):
        '''视图函数调用之后,内容返回浏览器之前调用。最后必须返回return response'''

        print('___process_response___')
        return response

实验结果:Python:Django3.1 框架学习笔记_第51张图片

·

15. 上传图片

15.1 上传图片时必要的配置

1)在项目中或者静态文件下创建media文件
Python:Django3.1 框架学习笔记_第52张图片

2)在settings.py中加上MEDIA_ROOT配置

# 配置文件上传保存目录
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/media')

15.2 从后台管理页面上传:

1)在models.py 中设计模型类

class image(models.Model):
    '''从后台上传图片'''
    # upload_to 指定文件上传的地址
    img = models.ImageField(upload_to='static/media/image')

2)在admin.py 中注册该模型类,则可通过后台管理页面上传图片
Python:Django3.1 框架学习笔记_第53张图片
·

·

15.3 浏览器自定义页面上传图片

1)创建模板文件,定义上传图片的表单


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传图片title>
head>
<body>

<form method="post" enctype="multipart/form-data" action="{% url 'comment:upload_handle' %}">
    {% csrf_token %}
    <input type="file" name="pic"><br/>
    <input type="submit" value="上传">
form>
body>
html>

2)在视图函数中进行上传图片的处理

。获取上传的图片
。创建一个文件
。获取上传文件的内容并写入创建的文件中
。在数据库中保存上传记录
。返回

def show_upload(request):
	'''显示上传图片页面'''
    print(settings.MEDIA_ROOT)
    return render(request, 'middle_test/show_upload.html')

def upload_handle(request):
	'''上传图片处理'''
	
	# 获取上传的图片对象
    pic = request.FILES['pic']

    # pic.chunks() 返回一个生成器,存储该文件的内容
    load = '%s/image/%s' % (settings.MEDIA_ROOT, pic.name)
    
	# 在media/image目录下创建该图片文件,并通过chunks()函数获取文件内容
    with open(load, 'wb') as f:
    	# 这里返回一个生成器需要通过遍历才可以得到内容
        for content in pic.chunks():
            f.write(content)
	
	# 在数据库中添加该上传记录
    image.objects.create(img='static/media/image/%s' % pic.name)

    return HttpResponse('上传成功')

·

·

16. 分页

16.1 关于分页的方法和属性

from django.core.paginator import Paginator

paginator = Paginator(数据对象, 按多少条数据进行分页)

Paaginator类对象属性:

属性名 说明
paginator.num_pages 返回分页之后的总页数
paginator.page_range 返回分页后页码的列表

Paaginator类对象方法:

方法名 说明
paginator.page(self, number) 返回第number页的Page类实例对象

Page类对象的属性:

属性名 说明
number 返回当前页的页码
object_list 返回包含当前页的数据的查询集
paginator 返回对应的Paginator类对象

Page类对象的方法:

方法名 说明
has_previous 判断当前页是否有前一页
has_next 判断当前页是否有后一页
previous_page_number 返回前一页的页码
next_page_number 返回后一页的页码

·

·

实例代码:

show_area.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>显示所有地区title>
head>
<body>

{% for area in page %}
<li>{{ area.area_name }}li>
{% endfor %}
{% if page.has_previous %}
<a href="/show_area{{ page.previous_page_number }}"><上一页a>
{% endif %}
{% for pindex in pageRange %}
    {% if pindex == page.number %}
    {{ pindex }}
    {% else %}
    <a href="/show_area{{ pindex }}">{{ pindex }}a>
    {% endif %}
{% endfor %}

{% if page.has_next %}
<a href="show_area{{ page.next_page_number }}">下一页>a>
{% endif %}
body>
html>

views.py

rom django.core.paginator import Paginator


def show_area(request, pindex):
    '''分页'''
    areas = AreaInfo.objects.all()

    # 创建Paginator对象,进行分页,每页显示10条
    paginator = Paginator(areas, 50)

    if pindex == '':
        pindex = 1
    else:
        pindex = int(pindex)
    # 获取第一页的内容,page时Page类的实例对象
    page = paginator.page(pindex)

    # 当页数过多时,进行缩减处理
    if pindex-5 < 1:
        pageRange = range(1, 11)
    elif pindex+5 > paginator.num_pages:
        pageRange = range(pindex-5, paginator.num_pages+1)
    else:
        pageRange = range(pindex-5, pindex+5)
    return render(request, 'booktest/show_area.html', locals())

urls.py

from django.urls import re.path
urlpatterns = [
    re_path(r'^show_area(?P\d*)$', views.show_area),
]

实验结果:
Python:Django3.1 框架学习笔记_第54张图片

·

·

16. Django自带缓存

设置缓存

缓存系统需要少量的设置。也就是说,你必须告诉它你的缓存数据应该放在哪里 —— 是在数据库中,还是在文件系统上,或者直接放在内存中。这是一个重要的决定,会影响你的缓存的性能;有些缓存类型比其他类型快。

官方文档说明详细,可分多种情况进行缓存,点击如下链接:
https://docs.djangoproject.com/zh-hans/3.2/topics/cache/

·

·

.MVT综合代码实例(test1为主项目,booktest为应用)

booktest/admin.py

from django.contrib import admin
from booktest.models import BookInfo, HeroInfo


# Register your models here.


class BookInfoAdmin(admin.ModelAdmin):
    list_display = ['id', 'btitle', 'bpub_date']


class HeroInfoAdmin(admin.ModelAdmin):
    list_display = ['id', 'hname']


admin.site.register(BookInfo, BookInfoAdmin)
admin.site.register(HeroInfo, HeroInfoAdmin)

·

·

booktest/models.py

from django.db import models


# Create your models here.

class BookInfo(models.Model):
    """书本信息"""
    btitle = models.CharField(max_length=20)
    bread = models.IntegerField(default=0)
    bpub_date = models.DateTimeField()
    isDelete = models.BooleanField(default=False)


class HeroInfo(models.Model):
    """英雄角色信息"""
    hname = models.CharField(max_length=20)
    hcomment = models.CharField(max_length=20)
    isDelete = models.BooleanField(default=False)

    # 设置外键,参数中必须指明 on_delete
    hbook = models.ForeignKey('BookInfo', on_delete=models.CASCADE)


class AreaInfo(models.Model):
    """自关联全国地区信息"""
    area_name = models.CharField(max_length=100)

    # 设置自关联外键,null表示该字段在数据库中可以为空,blank表示后台管理页面中该字段可以为空白,必须指明on_delete
    area_parent = models.ForeignKey('AreaInfo', null=True, blank=True, on_delete=models.CASCADE, db_constraint=False)


·

booktest/urls.py

from django.urls import path
from booktest import views

urlpatterns = [
    path('books', views.books_display, name='books_display'),
    path('books/', views.hero_display, name='hero_display'),
    path('create', views.create, name='create'),
    path('delete/', views.delete, name='delete'),
    path('area', views.area_view, name='area_view'),

]

·

booktest/views.py

from django.shortcuts import render
from booktest.models import BookInfo, HeroInfo, AreaInfo
from django.shortcuts import redirect
from django.utils import timezone
from django.http import HttpResponseRedirect


# Create your views here.

def books_display(request):
    books = BookInfo.objects.all()

    return render(request, 'booktest/books_display.html', {'books': books})


def hero_display(request, bid):
    book = BookInfo.objects.get(id=bid)
    heros = book.heroinfo_set.all()

    return render(request, 'booktest/hero_display.html', {'heros': heros})


def create(request):
    b = BookInfo(
        btitle='灵剑封魔录',
        bread=125,
        bpub_date=timezone.now()  # 显示当前时间
    )
    b.save()
    return redirect('/books')  # 重定向到该url
    # return HttpResponseRedirect('/books')


def delete(request, bid):
    b = BookInfo.objects.get(id=bid)
    b.delete()

    return redirect('/books')


def area_view(request):
    area = AreaInfo.objects.get(area_name="广州市")
    area_parents = area.area_parent.area_name
    area_child = area.areainfo_set.all()
    return render(request, 'booktest/area_display.html', {'area': area, 'area_parent': area_parents, 'areas_child':area_child})

·

test1/__ init__.py

import pymysql

# 指定版本
pymysql.version_info = (1, 4, 13, "final", 0)

# 将pymysql伪装成mysqlclient
pymysql.install_as_MySQLdb()

·

templates/booktest/books_display.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>显示图书信息</title>
</head>
<h3>图书信息:</h3>
<a href="/create">新增</a>
<body>
{% for book in books %}
        <li><a href="/books/{{ book.id }}">{{ book.btitle }}</a>---{{ book.bpub_date }}
            <a href="/delete/{{ book.id }}">删除</a></li>
{% endfor %}
</body>
</html>

·

templates/booktest/hero_display.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>英雄角色信息显示</title>
</head>
<body>
<h3>关联英雄角色信息:</h3>
{% for hero in heros %}
    <li>{{ hero.hname }}---{{ hero.hcomment }}</li>
    {% empty %}
    <li>没有关联的英雄角色</li>
{% endfor %}

</body>
</html>

·

templates/booktest/area_display.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>广东省上下级城市</title>
</head>
<body>
<h1>当前地区</h1>
{{ area.area_name }}
<h1>父级地区</h1>
{{ area_parent }}
<h1>下级地区</h1>
{% for i in areas_child %}
<li>{{ i.area_name }}</li>
{% endfor %}
</body>
</html>

·

test1/urls

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

# 项目的url文件
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('booktest.urls'))
]

·

实验结果:
Python:Django3.1 框架学习笔记_第55张图片

Python:Django3.1 框架学习笔记_第56张图片

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