Django介绍

介绍

Django是Python语言中的一个Web框架,Python语言中主流的 web框架有Django、Tornado、Flask 等多种

优势 :大而全,框架本身集成了ORM、模型绑定、模板引擎、缓 存、Session等功能,是一个全能型框架,拥有自己的Admin数据管 理后台,第三方工具齐全,性能折中

缺点 :功能太多,数据分表复杂,高性能扩展复杂、重量级

Django 是开源的

安装

python3.8+

pip安装:在cmd命令窗口中,输入:

1 ==4.1.1 pip install django

文档

官方文档的链接在:https://docs.djangoproject.com

提示

  • 点击页面右下角的 language 按钮,可以选择 zh-hans ,显示中文,只有部分页面有中文翻 译

  • 点击页面右下角的Documentation version,可以选择版本

专业词汇

B/S和C/S

Django是用于开发B/S架构的软件的,软件主要分为B/S架构和C/S 架构:

  • B/S:全称Browser/Server(浏览器/服务器)

  • C/S:全称Client/Server(客户端/服务器)

MVC

MVC全名是Model View Controller,是模型(model)-视图(view) -控制器(controller)的缩写,一种软件设计典范,用一种业务逻 辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个 部件里面,在 改进个性化定制界面及用户交互 的同时, 不需要重 新编写业务逻辑

  • M:管理应用程序的状态(通常存储到数据库中),并约束改变状态的行为(或者叫做“业务规 则”)。

  • V: 负责把数据格式化后呈现给用户。

  • C: 接受外部用户的操作,根据操作访问模型获取数据,并调用“视图”显示这些数据。控制器是将 “模型”和“视图”隔离,并成为二者之间的联系纽带。

MTV

Django也是一个MVC框架。但是在Django中,控制器接受用户输 入的部分由框架自行处理,所以 Django 里更关注的是模型

  • (Model)、模板(Template)和视图(Views),称为 MTV模式:

    • M: 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验 证有效性、包含哪些行为以及数据之间的关系等。

    • T: 代表模板(Template),即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中 进行显示。

    • V: 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑。 你可以 把它看作模型与模板之间的桥梁。

ORM

ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术, “ “ - 是 对象 关系映射 (Object/Relational Mapping) 的缩写

ORM 把数据库映射成对象

举例来说,下面是一行 SQL 语句。

  • 1 SELECT id, first_name, last_name, phone, birth_date, sex

  • 2 FROM persons 3 WHERE id = 10

程序直接运行 SQL,操作数据库的写法如下。

  • 1 res = db.execSql(sql);

  • 2 name = res[0]["FIRST_NAME"];

改成 ORM 的写法如下。

  • 1 p = Person.get(10); 2 name = p.first_name;

一比较就可以发现,ORM 使用对象,封装了数据库操作,因此可 以不碰 SQL 语言。开发者只使用面向对象编程,与数据对象直接交 互,不用关心底层数据库

ORM 有下面这些优点

  • 数据模型都在一个地方定义,更容易更新和维护,也利于重用代码

  • ORM 有现成的工具,很多功能都可以自动完成,比如数据初始化、事务等等

  • 它迫使你使用 MVC 架构,ORM 就是天然的 Model,最终使代码更清晰

  • 基于 ORM 的业务代码比较简单,代码量少,语义性好,容易理解

  • 不必编写性能不佳的 SQL

ORM 也有很突出的缺点

  • ORM 库不是轻量级工具,需要花很多精力学习和设置

  • 对于复杂的查询,ORM 要么是无法表达,要么是性能不如原生 的 SQL

  • ORM 抽象掉了数据库层,开发者无法了解底层的数据库操作, 也无法定制一些特殊的 SQL

Django项目搭建

创建项目

在命令行中执行代码

1 $ django-admin startproject mysite

  • django-admin 为内部命令

  • startproject 为参数

  • mysite 项目名

备注

避免使用 Python 或 Django 的内部保留字来命名项目。比如 说,避免使用像 django (会和 Django 自己产生冲突)或 test (会和 Python 的内置组件产生冲突)这样的名字

项目结构

  • 1 mysite/ # 项目的名称

  • 2 manage.py # 管理 Django 项目的命令行工具,启 动和结束等

  • 3 mysite/ # 项目主应用 , 它是一个 Python 包 4 __init__.py # 一个空文件 , 告诉 Python 这个 目录是一个 Python 包

  • 5 settings.py # 项目的配置文件,有关于数据 库、编码、时区等

  • 6 urls.py # 项目的 url 路由配置,即 url 路由与 其函数的对应配置

  • 7 wsgi.py # 用于项目与 WSGI 兼容的 Web 服务器入 口,用于项目部署

启动项目

命令行窗口中,进入最外层的mysite

运行命令

python manage.py runserver

额外参数

python manage.py runserver 8081

python manage.py runserver 127.0.0.1:8082

一 第 个Django程序

==> picture [13 x 9] intentionally omitted <==

—– Start of picture text —–

12
—– End of picture text —–

==> picture [372 x 433] intentionally omitted <==

—– Start of picture text —–

了解请求流程
RIF isKET
—_ WY J oN,
| |
ee
创建一个子应用
1 $ python manage.py startapp myapp01
修改settings.py配置
—– End of picture text —–

- 实战 开发登录表单

==> picture [399 x 159] intentionally omitted <==

—– Start of picture text —–

1 def login_form(request):
‘’’
2 html =
3
4
5


6 用户名 :<input name = “username”
type=”text”>

—– End of picture text —–

7 密码: <input name = "password" type = "password"></input></br>

8 <input type="submit" value=" 登录 "> </input> 9 </form> 10 </body> 11 </html> 12 13 ''' 14 return HttpResponse(html)

- Django配置文件 初识

介绍

Django项目创建后,在主应用中,会有一个settings.py文件,这个 就是该项目的配置文件

settings文件包含Django安装的所有配置

  • settings文件是一个包含模块级变量的python模块,所以该模块本身必须符合python规则,并且可 以使用python的语法

settings中的所有配置项的key必须全部大写

  • settings中每一个配置项都有默认值,默认配置内容在django/conf/global_settings.py中可以查看 到,项目中不需要导入该模块,django框架会自动获取

settings中可以添加自定义的配置项

配置文件的使用

e 1 manage.py启动 默认在manage.py中配置:

1 if __name__ == "__main__": 2 os.environ.setdefault("DJANGO_SETTINGS_MO DULE", "firstdjango.settings")

e 2 手动指定配置文件位置 cmd命令启动如下:

1 python manage.py runserver -- settings=firstdjango.settings

@ 3 服务器部署启动

在wsgi.py中配置:

1 os.environ.setdefault("DJANGO_SETTINGS_MOD ULE", "firstdjango.settings")

程序中获取配置项

如果在项目代码中需要获取settings中的配置项,这样获取:

1 # 切记不要导入具体的 settings 模块的路径,会形成高耦合 2 # 这样的方式是不可取的: from mysite import settings

3 from django.conf import settings 4

  • 5 d = settings.DEBUG

- Django配置文件 常用配置项

==> picture [101 x 15] intentionally omitted <==

—– Start of picture text —–

1 import os
—– End of picture text —–

==> picture [46 x 57] intentionally omitted <==

—– Start of picture text —–

2
3
“””
4
—– End of picture text —–

  • 5 当前文件所在文件夹的上一级目录的绝对路径 6 切记 2 个 os.path.dirname """

  • 7 8 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abs path(__file__)))

path(file)))(file)))file))))))
9
10 “””
11 用于加密session,一个随机的字符串
12 这样生成:
13 from django.core.management import
utils
14 utils.get_random_secret_key()
15 “””
16 SECRET_KEY =
‘=*f&bx760nyar7@8lb8!w$9h(3ea6p3apl$iua!td1
q%-u5r4=’
17
18 #调试模式,可以看到错误的所有相信信息,部署时一定要
修改为False
19 DEBUG = True
20
21 “””
22 允许访问的域名设置
23 开发环境不用理会
24 运行环境,配置DEBUG = False后,
25 如果允许所有域名访问,则设置ALLOW_HOSTS =
[‘*’]
26 如果指定某些域名可以访问,则设置ALLOW_HOSTS
= [‘*.baidu.com’]
27 “””
28 ALLOWED_HOSTS =[]

29 30 """ 31 32 应用的配置, 33 如: 'polls.apps.PollsConfig' 34 如果没有 PollsConfig ,那么可以配置为 'polls' """ 35 36 INSTALLED_APPS = [ 37 'django.contrib.admin', 38 'django.contrib.auth', 39 'django.contrib.contenttypes', 40 'django.contrib.sessions', 41 'django.contrib.messages', 42 'django.contrib.staticfiles', # 只有 DEBUG = Ture 才有效 43 44 'polls' # 子应用必须配置,否则不起作用 45 ] 46 """ 47 48 中间件 49 自己编写的 中间层 需要配置在最后 50 譬如: 51 mymidlle.md.TestMiddleware """ 52 53 MIDDLEWARE = [ 54 'django.middleware.security.SecurityMiddle ware',

55

'django.contrib.sessions.middleware.Sessio nMiddleware',

56 'django.middleware.common.CommonMiddleware ' , 57 'django.middleware.csrf.CsrfViewMiddleware ' , 58 'django.contrib.auth.middleware.Authentica tionMiddleware', 59 'django.contrib.messages.middleware.Messag eMiddleware', 60 'django.middleware.clickjacking.XFrameOpti onsMiddleware', 61

62 ] 63 64 # 配置基础的 urls 65 ROOT_URLCONF = 'firstdjangopy.urls' 66 67 # 配置模板 68 TEMPLATES = [ 69 { 70 'BACKEND': 'django.template.backends.django.DjangoTemp lates', 71 'DIRS': [os.path.join(BASE_DIR, 'templates')]

72 , ,
73 ‘APP_DIRS’:True,
74 ‘OPTIONS’: {
75 ‘context_processors’: [
76
‘django.template.context_processors.debug’
,
77
‘django.template.context_processors.reques
t’,
78
‘django.contrib.auth.context_processors.au
th’,
79
‘django.contrib.messages.context_processor
s.messages’,
80 ], ],
81 }, },
82 }, },
83 ]
84
85 #服务器部署的WSGI配置
86 WSGI_APPLICATION =
‘firstdjango.wsgi.application’
87
88
89 “””
90 数据库配置
91 mysql mysql在python3的使用,需要在__init__.py
中加入以下代码:
92 import pymysql import pymysql
93

94 pymysql.install_as_MySQLdb() """ 95

96 # DATABASES = { 97 # 'default': { 98 # 'ENGINE': 'django.db.backends.sqlite3', 99 # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 100 # } 101 # } 102 DATABASES = { 103 'default': { 104 'ENGINE': 'django.db.backends.mysql', 105 'NAME': 'django_test1', 106 'USER': 'root', 107 'PASSWORD': '123456', 108 'HOST': '127.0.0.1', 109 'PORT': '3306', 110 } 111 }

112 113 """ 114 115 用户密码验证 """ 116 117 AUTH_PASSWORD_VALIDATORS = [ 118 { 119 'NAME': 'django.contrib.auth.password_validation.Us erAttributeSimilarityValidator', 120 },

121

{

122 'NAME': 'django.contrib.auth.password_validation.Mi nimumLengthValidator', 123 }, 124 { 125 'NAME': 'django.contrib.auth.password_validation.Co mmonPasswordValidator', 126 }, 127 { 128 'NAME': 'django.contrib.auth.password_validation.Nu mericPasswordValidator', 129 }, 130 ] 131 132 133 # 语言选择 , zh-Hans 为中文 134 LANGUAGE_CODE = 'en-us' 135 136 # 时区 Asia/Shanghai 是中国时区 137 TIME_ZONE = 'UTC' 138 139 # 国际化 140 USE_I18N = True 141 142 # 本地化 143 USE_L10N = True 144 145 # 使用时区,配套 TIME_ZONE 使用,必须设置为 False 146 USE_TZ = False

147 """ 148

149 静态文件的路径,默认是 static 150 如果在各自项目的 static 目录以外,还有目录存放静 态文件,需要添加如下属性: 151 STATICFILES_DIRS = ( 152 os.path.join(BASE_DIR, "common_static1"), 153 '/var/www/static/', 154 ) """ 155 156 STATIC_URL = '/static/'

- URL调度器 介绍

介绍

当一个用户请求 Django 站点的一个页面,下面是 Django 系统决定 执行哪个 Python 代码使用的算法:

  • Django确定要使用的根URLconf模块,一般是在settings中的 ROOT_URLCONF设置的值,但是如果传入 HttpRequest 对象具 有一个urlconf 属性(由中间件设置),则其值将用于代替 ROOT_URLCONF设置。

  • Django加载该URLconf模块并查找变量 urlpatterns,它是一个 列表django.urls.path() 和 / 或django.urls.re_path()实例。

  • Django按顺序遍历每个URL模式,并停在与请求的URL匹配的第 一个URL模式,需要特别注意编写的顺序

  • 一旦某个URL模式匹配,Django就会导入并调用给定的视图, 该视图是一个简单的Python函数(或基于类的视图方法)。该 视图通过以下参数传递:

一个HttpRequest实例。

  • 如果匹配的URL模式没有返回任何命名组,则来自正则表达式的匹配作为位置参数提供。 关键字参数由路径表达式匹配的任何命名部分组成,并由可选的kwargs参数传给 django.urls.path()或django.urls.re_path()。

  • 如果没有URL模式匹配,或者在此过程中的任何点发生异常, Django将调用适当的错误处理视图

- URL调度器 基本使用

配置子应用urls.py

1 from django.urls import path

2

  • 3 urlpatterns = [

  • 4 path('user/',user),

  • 5 path('user/info/',user_info),

  • 6 path('user/<id>/',user_id),

  • 7 path('user/<id>/<year>/',user_id_year),

  • 8 path('user/<int:id>/',user_int),

  • 9 ]

注意

  • 从URL中捕获值,请使用尖括号

  • 捕获的值可以选择包含转换器类型。例如,用于 int:name捕获,前面的int指整数参数, name是参数的名称

  • 没有必要添加一个前导斜杠,因为每个URL都有,例如,使用articles而不是/articles

路径转换器

  • str:匹配任何非空字符串,不包括路径分隔符’/‘。如果转换器不包含在表达式中,这是默认值。 int:匹配零或任何正整数。返回一个int。

  • slug:匹配由ASCII字母或数字组成的字符串,以及横线和下划线字符。例如: building-your-1stdjango_site可以匹配,django_@site是不可以匹配的。

  • uuid:匹配格式化的UUID。为防止多个URL映射到同一页面,必须包含破折号,并且字母必须是 小写。例如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID实例。

  • path:匹配任何非空字符串,包括路径分隔符 ‘/‘,可以匹配完整的URL路径,而不仅仅是URL路径 的一部分str,使用时要谨慎,因为可能造成后续的所有url匹配都失效。

  • 1 path('articles/<uuid:uuid>/',views.article_uu id),

  • 1 # 获取 uuid

  • 2 import uuid

  • 3 print(uuid.uuid1())

- URL调度器 自定义路径转换器

转换器是一个包含以下内容的类:

一个regex类属性,作为一个re匹配字符串

  • to_python(self, value)方法,它处理匹配的字符串转换成要传递 到视图函数的类型

29 to_url(self, value)方法,用于处理将Python类型转换为URL中使 用的字符串

定义方式如下:

rd) 1 新建一个converters.py文件,在文件中定义一个 FourDigitYearConverter类:

1 class FourDigitYearConverter(object): 2 regex = '[0-9]{4}' 3 4 def to_python(self, value): 5 return int(value) 6 7 def to_url(self, value): 8 return '%04d' % value

e 2 使用register_converter()方法在URLconf中注册自定义转换器类 :

1 from django.urls import register_converter, path

2 3 from . import converters, views 4 5 register_converter(converters.FourDigitYea rConverter, 'yyyy') 6 7 urlpatterns = [ 8 path('articles/2030/', views.special_case_2030), 9 path('articles/<yyyy:year>/', views.year_archive) 10 ]

- URL调度器 使用正则表达式

使用正则表达式匹配路径,请使用 re_path()而不是path()

在Python正则表达式中,命名正则表达式组的语法是(? Ppattern),其中name是组的名称,并且pattern是一些要 匹配的模式

案例代码

  • 1 from django.urls import path, re_path 2 3 from . import views 4 5 # url() 是 re_path 的别名,不推荐使用 6 urlpatterns = [

  • 7 re_path(r'^articles/(?P<year>[0-9] {4})/$', views.year_archive),

  • 8 re_path(r'^articles/(?P<year>[0-9] {4})/(?P<month>[0-9]{2})/$', views.month_archive),

9 # 不推荐 , 匹配 blog/page-3/ 10 re_path(r'^blog/(page-(\d+)/)?$', blog_articles),

11 # 推荐 ,匹配: comments/page-2/ 路径到 comments(request, page_numer)

12 re_path(r'^comments/(?:page-(? P<page_number>\d+)/)?$', comments), 13 ] 14

注意事项

  • 无论正则表达式匹配什么类型,每个捕获的参数都以字符串的形式发送到视图

  • 除了命名的组语法,例如(?P[0-9]{4}),也可以使用较短的未命名组,例如([0-9]{4}), 但是不建议这样使用,会引起未知的匹配

- URL调度器 默认值与额外参数

默认值

urls.py

  • 1 from django.urls import path 2 3 from . import views 4

  • 5 urlpatterns = [

  • 6 # http://127.0.0.1:8000/polls/blog/ 等同 于

  • 7 # http://127.0.0.1:8000/polls/blog/1/

  • 8 path('blog/', views.page), 9 # http://127.0.0.1:8000/polls/blog/1/

  • 10 # http://127.0.0.1:8000/polls/blog/10/ 11 # http://127.0.0.1:8000/polls/blog/99/

  • 12 path('blog/<int:num>/', views.page), 13 ]

views.py

  • 1 def page(request, num=1): 2 # 编写对应的业务逻辑

额外的参数

urls.py

1 from django.urls import path 2 from . import views 3 4 urlpatterns = [ 5 # 会传递给 views. 6 path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}), 7 ] views.py

1 def year_archive(request, year=2005, foo='bar') 2 # 编写对应的业务逻辑

- URL调度器 错误处理

handler400- 状态码400 handler403- 状态码403 handler404- 状态码404 handler500- 状态码500

  • @ 1 在 settings中修改配置: 1 DEBUG = False 2 3 ALLOWED_HOSTS = ['*']

  • @ 2 在主应用的urls中配置: 1 # polls 是子应用 2 handler404 = "polls.views.page_not_found"

  • @ 3 在polls应用的views中添加函数page_not_found: 1 def page_not_found(request, exception): '

  • 2 return HttpResponse( 自定义的 404 错误页 面 ')

. 4 浏览器测试访问,找不到匹配的路由

- URL调度器 引用其他URL调度器

include(str)

  • 1 from django.urls import include, path 2 3 urlpatterns = [ 4 path('community/', include('aggregator.urls')),

  • 5 path('contact/', include('contact.urls')),

  • 6 ]

include(list/tuple)

1 from django.urls import include, path 2 3 from apps.main import views as main_views 4 from credit import views as credit_views 5 6 extra_patterns = [ 7 path('reports/', credit_views.report), 8 path('reports/<int:id>/', credit_views.report), 9 path('charge/', credit_views.charge), 10 ] 11 12 urlpatterns = [ '' 13 path( , main_views.homepage), 14 path('help/', include('apps.help.urls')), 15 path('credit/', include(extra_patterns)), 16 ]

技巧

优化繁琐的URL地址编写

1 from django.urls import path 2 from . import views 3

  • 4 urlpatterns = [

  • 5 path('<page_slug>-<page_id>/history/', views.history),

6 path('<page_slug>-<page_id>/edit/', views.edit),

7 path('<page_slug>-<page_id>/discuss/', views.discuss),

8 path('<page_slug><page_id>/permissions/', views.permissions), 9 ]

优化

1 from django.urls import include, path 2 from . import views 3 4 urlpatterns = [ 5 path('<page_slug>-<page_id>/', include([ 6 path('history/', views.history), 7 path('edit/', views.edit), 8 path('discuss/', views.discuss), 9 path('permissions/', views.permissions), 10 ])), 11 ]

URL调度器-URL反向解析

url调度器除了从用户发起请求,到匹配对应的view,还能在

python程序中调用进行匹配,通过 path或re_path 中 的name属性 进行解析

在模板中,使用url模板标签

在Python代码中(主要是views),使用 reverse() 函数

示例

urls中配置

1 from django.urls import path 2 3 from . import views 4 5 urlpatterns = [ 6 #... 7 path('articles/<int:year>/', views.year_archive, name='news-yeararchive'), 8 #... 9 ]

在模板中测试

views.py跳转到页面

1 def do_html(request): 2 return render(request,'redirect_test.html')

  • 3 4 def year_archive(request,year):

  • 5 return HttpResponse(f' 重定向成功 {year}')

模板中代码

  • 1 # 模板中:

  • 2 <a href="{% url 'news-year-archive' 2030 %}">2030 Archive</a>

在python代码测试

  • 1 from django.urls import reverse 2 from django.http import HttpResponseRedirect 3

  • 4 def redirect_to_year(request): 5 return HttpResponseRedirect(reverse('news-yeararchive', args=(2030,)))

- URL调度器 命名空间

命名空间主要用于配合url反向解析使用,多个不同的urls文件中可 能配置同名的 name,那么为了进行区分,给不同的urls进行不同 的命名

注意 同一个项目下命名空间不能重复,切记!

命名空间基本使用

通过在 url调度器的模块中,定义 app_name = ‘polls’ 来命名

  • 1 from django.urls import path

  • 2 from . import views

3

  • 4 # 定义,一般命名空间和子应用名相同,便于记忆 5 app_name = 'polls' 6 urlpatterns = [ ''

  • 7 path( , views.index_view, name='index'),

  • 8 path('<int:pk>/', views.detail_view, name='detail'),

  • 9 ...

  • 10 ] 11 # 调用,一旦有了命名空间,调用时就必须使用 polls : 前缀

  • 12 reverse('polls:index')

命名空间嵌套

  • 1 # 在 urls 中配置如下: 2 from django.urls import path 3 from . import views

  • 4

  • 5 # 定义命名空间,一般命名空间名和子应用名相同,便于记 忆

  • 6 app_name = 'polls'

  • 7 extra_patterns = (

  • 8 [

  • 9 path('app_name/', views.app_name, name='app_name'),

  • 10 ], 11 # 此处就是嵌套的命名空间

  • 12 'extra'

  • 13 )

14 urlpatterns = [ '' 15 path( , views.index_view, name='index'), 16 path('<int:pk>/', views.detail_view, name='detail'), 17 path('extra/', include(extra_patterns)), 18 ... 19 ] 20 # 在模板中使用: 21 <a href="{% url 'polls:extra:app_name' %}"> 点击链接 </a>

- Django模型 介绍

模型,就是python中的类对应数据库中的表

ORM

ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术, “ “ - 是 对象 关系映射 (Object/Relational Mapping) 的缩写

ORM 把数据库映射成对象

示例

模型

  • 1 from django.db import models

  • 2

  • 3 class Person(models.Model): 4 first_name = models.CharField(max_length=30)

  • 5 last_name = models.CharField(max_length=30)

数据库表

  • 1 CREATE TABLE myapp_person ( 2 "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,

  • 3 "first_name" varchar(30) NOT NULL, 4 "last_name" varchar(30) NOT NULL 5 );

说明

e 1 模型类必须继承models.Model

  • @ 2 每个属性对应数据库表中的一个字段

  • e 3 表名自动使用 应用_类名 的小写(如:polls_question),可以覆盖重写

  • @ 4 如果模型类中没有指定 primary_key ,那么会自动创建一个 id 字段,自增,主键

Django模型-MySQL数据库迁移

==> picture [458 x 225] intentionally omitted <==

—– Start of picture text —–

48
mys
OO Exes |
当编写了模型之后,需要将模型应用到数据库中,具体步骤如下:
—– End of picture text —–

  • 1 创建项目model_study,及子应用model_app

    • 1 # 创建项目 2 $ django-admin startproject model_study 3 # 进入项目目录创建子应用 4 $ python manage.py startapp model_app
  • 2 配置应用,将模型对应的应用程序添加到项目的settings中:

    • 1 INSTALLED_APPS = [ 2 'model_app' 3 ]
  • 3 在settings.py中配置正确的数据库连接:

==> picture [297 x 279] intentionally omitted <==

—– Start of picture text —–

1 # mysql
2 DATABASES = {
3 ‘default’: {
4 ‘ENGINE’:
‘django.db.backends.mysql’,
5 ‘NAME’: ‘model_study’,
6 ‘USER’: ‘root’,
7 ‘PASSWORD’: ‘root’,
8 ‘HOST’: ‘127.0.0.1’,
9 ‘PORT’: 3306,
10 }
11 }
—– End of picture text —–

注意 e@ 需要安装对应数据库的驱动 e pip install mysqlclient==2.1.1 e pip install pymysql 1 # __init__.py 2 import pymysql 3 pymysql.install_as_MySQLdb() e 需要在mysql数据库中创建数据库model_study

创建迁移

在项目根目录的cmd中运行:

1 $ python manage.py makemigrations model_app

备注

  • @ 1 model_app是子应用的名称,如果不指定,那么就是对所有 INSTALLED_APPS 中的应用都 进行预备迁移

@ 2 指定该命令后,在对应的子应用下的 migrations 中会生成一个对应的迁移文件

正式迁移

在根目录的cmd中运行:

1 $ python manage.py migrate

备注

没有添加子应用名,那么就会把django项目中所有的应用都迁 移到数据库中

Django模型-sqlite3数据库迁移

当编写了模型之后,需要将模型应用到数据库中,具体步骤如下:

  • 1 创建项目model_study,及子应用model_app

  • 1 # 创建项目 2 $ django-admin startproject model_study 3 # 进入项目目录创建子应用 4 $ python manage.py startapp model_app

  • 2 配置应用,将模型对应的应用程序添加到项目的settings中:

    • 1 INSTALLED_APPS = [ 2 'model_app' 3 ]
  • 3 在settings.py中配置正确的数据库连接:

1 # sqlite3 2 DATABASES = { 3 'default': { 4 'ENGINE': 'django.db.backends.sqlite3', 5 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 6 } 7 }

注意

需要安装对应数据库的驱动

需要在mysql数据库中创建数据库model_study

创建迁移

在项目根目录的cmd中运行:

1 $ python manage.py makemigrations model_app

备注

e 1 model_app是子应用的名称,如果不指定,那么就是对所有 INSTALLED_APPS 中的应用都 进行预备迁移 e 2 指定该命令后,在对应的子应用下的 migrations 中会生成一个对应的迁移文件

正式迁移

在根目录的cmd中运行:

1 $ python manage.py migrate

备注

没有添加子应用名,那么就会把django项目中所有的应用都迁 移到数据库中

- Django模型 更新数据库表结构

不管是新增模型,还是修改已有模型后,只需要执行行命令即可:

创建迁移

在项目根目录的cmd中运行:

  • 1 $ python manage.py makemigrations model_app

备注

  • 1 model_app是子应用的名称,如果不指定,那么就是对所有 INSTALLED_APPS 中的应用都 进行预备迁移

  • 2 指定该命令后,在对应的子应用下的 migrations 中会生成一个对应的迁移文件

正式迁移

在根目录的cmd中运行:

  • 1 $ python manage.py migrate

备注

没有添加子应用名,那么就会把django项目中所有的应用都迁 移到数据库中

设置表名

在模型中建立内部类Meta设置db_table即可

  • 1 # Create your models here.

  • 2 class Person(models.Model): 3 first_name = models.CharField(max_length=10)

  • 4 lname = models.CharField(max_length=30)

  • 5 age = models.CharField(max_length=30)

  • 6

  • 7 class Meta:

  • 8 db_table = 't_person'

- Django模型 逆向从数据库表生成模型类

  • 1 settings中设置好 DATABASES 配置

  • 2 在对一个数据库中建立好表、约束和表关系等

  • 3 在根目录的cmd中运行:

    • 1 python manage.py inspectdb > model_app/models.py

model_app是子应用名

  • 4 第3步执行后会在models中生成对应的模型类
1 class DjangoSession(models.Model):
2 session_key =
models.CharField(primary_key=True,
max_length=40)
3 session_data = models.TextField()
4 expire_date = models.DateTimeField()
5
6 class Meta:
7 db_table = ‘django_session’ #对应
的数据库中的表名

- Django模型 字段介绍

模型类的属性对应数据库中表的字段,都是对应的Field类的实例

字段命名限制

  • 字母,数字,下划线,首字母不能是数字

  • 字段名称不能是Python保留字

  • 由于Django查询查找语法的工作方式,字段名称不能在一行中包含多个下划线,譬如“abc__123”就 是不允许的,一个下划线是可以的,如:’first_name’

主键的使用

默认会自动创建一个自增,主键的id列

如果指定了 primary_key 为其它列,那么不会自动创建id列

例如:

1 id = models.AutoField(primary_key=True)

常见的字段

字段名 作用
AutoField 自增一个IntegerField,根据可用的ID自动递增
BooleanField 该字段的默认表单部件是checkbox,默认值是None
CharField 一个字符串字段
DateField 一个日期,在Python中用一个
datetime.date 实例表示
DateTimeField 一个日期和时间,在Python中用一个
datetime.datetime 实例表示
FloatField 在Python中用一个
float 实例表示的浮点数
SmallIntegerField 就是一个IntegerField,
-32768 到
32767 的值
IntegerField 一个整数。从
-2147483648 到
2147483647 的值
TextField 一个大的文本字段。该字段的默认表单部件是一个Textarea

特别的说明

  • 1 import uuid

  • 2 from django.db import models

  • 3

  • 4 class MyUUIDModel(models.Model):

  • 5 # uuid.uuid4 千万别写成 uuid.uuid4() ,不要 写 ()

  • 6 id = models.UUIDField(primary_key=True, default=uuid.uuid4)

常见的属性

  • max_length:字段最大长度,用于字符串等,字符串类型 CharField必须设置该值

  • null:如果True,Django将在数据库中存储NULL空值。默认是 False

  • blank:如果True,该字段被允许为空白(“”)。默认是False。

注意

这不同于null。null纯粹是与数据库相关的,而blank与验证 相关。如果一个字段有blank=True,表单验证将允许输入一 个空值。如果一个字段有blank=False,该字段将是必需的

choices:

示例:YEAR_IN_SCHOOL_CHOICES = ((‘FR’, ‘Freshman’),(‘SO’, ‘Sophomore’),(‘JR’, ‘Junior’),(‘SR’, ‘Senior’),(‘GR’, ‘Graduate’)) , 中文示例:SEX_CHOICES=((1, ‘男’),(2, ‘女’))

元组中的第一个元素是将存储在数据库中的值,第二个元素是将 在页面中显示的值,最常见用于下拉选择框select

  • default:字段的默认值

  • help_text:用于显示额外的“帮助”文本

  • primary_key:如果True,这个字段是模型的主键,默认是 False

  • unique:如果True,该字段在整个表格中必须是唯一的

  • verbose_name:详细字段名,不指定则是属性名的小写,并且 用 空格 替换 ‘_’

Django模型-1对1关系映射

关系型数据库的强大之处在于各表之间的关联关系。 Django 提供 了定义三种最常见的数据库关联关系的方法:多对一,多对多,一 对一

一对一关联使用 OneToOneField来定义一对一关系

就像使用其他类型的 Field 一样:在 任意一边模型 属性中包含它

  • 1 from django.db import models

  • 2 3 class Place(models.Model): 4 name = models.CharField(max_length=50) 5 address = models.CharField(max_length=80)

6 7 def __str__(self):

8 return “%s the place” % self.name
9
10 class Restaurant(models.Model):
11 place = models.OneToOneField(
12 Place,
13 on_delete=models.CASCADE,
14 primary_key=True,
15 )
16 # BooleanField在数据库使用tinyint类型
17 serves_hot =
models.BooleanField(default=False)
18 serves_clod=
models.BooleanField(default=False)
19
20 def str(self):
21 return “%s the restaurant” %
self.place.name

Django模型-1对多关系映射

定义一个多对一的关联关系,使用 django.db.models.ForeignKey 类。就和其它 Field字段类型一样,只需要在你模型中添加一个值为 该类的属性

ForeignKey类需要 多的一方 添加一个参数,即你想要关联的模型类 名

  • 1 from django.db import models 2 3 class Place(models.Model): 4 name = models.CharField(max_length=50) 5 address = models.CharField(max_length=80)

  • 6 7 def __str__(self):

8

return "%s the place" % self.name

9

  • 10 class Restaurant(models.Model): 11 place = models.OneToOneField( 12 Place, 13 on_delete=models.CASCADE, 14 primary_key=True, 15 )

  • 16 # BooleanField 在数据库使用 tinyint 类型 17 = serves_hot_dogs

  • models.BooleanField(default=False)

  • 18 serves_pizza = models.BooleanField(default=False)

  • 19 20 def __str__(self): 21 return "%s the restaurant" % self.place.name

  • 22 23 class Waiter(models.Model): 24 restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)

  • 25 name = models.CharField(max_length=50) 26 27 def __str__(self): 28 return "%s the waiter at %s" % (self.name, self.restaurant)

- Django模型 多对多关系映射

定义一个多对多的关联关系,使用

django.db.models.ManyToManyField 类。就和其他Field字段类型 一样,只需要在你模型中添加一个值为该类的属性

ManyToManyField类需要 任意模型边 添加一个位置参数,即你想要 关联的模型类名

  • 1 class SchoolClass(models.Model): 2 name = models.CharField(max_length=20) 3 4 class Teacher(models.Model): 5 name = models.CharField(max_length=10) 6 school_class = models.ManyToManyField(SchoolClass)

- Django模型 多对多关系自定义中间表

  • 1 from django.db import models

  • 2 3 class Person(models.Model): '''

  • 4 5 人 6 ''' 7 name = models.CharField(max_length=32)

  • 8 9 class Language(models.Model): '''

  • 10 11 学习的语言 12 ''' 13 name = models.CharField(max_length=32)

  • 14 # 建立多对多管理的使用 15 person_language = models.ManyToManyField(

  • 16 Person, 17 through = 'PersonLanguage', # 这是一个 字符串,

  • 18 )

  • 19 20 class PersonLanguage(models.Model):

''' 21

22 人学了哪门语言 23 ''' 24 person =

models.ForeignKey(Person,on_delete=models.CA SCADE)

25 language =

models.ForeignKey(Language,on_delete=models. CASCADE)

26 level = models.IntegerField(default=1)

- Django模型 自关联

自关联就是外键指向自己表模型

一对多应用

省市区级联

  • 1 from django.db import models

  • 2

  • 3 class Area(models.Model):

  • 4 name = models.CharField(max_length=32)

  • 5 pid = models.ForeignKey('self', on_delete=models.CASCADE)

多对多应用

主播与粉丝的关系

链接与友情链接

  • 1 from django.db import models

  • 2

  • 3 class Person(models.Model):

  • 4 friends = models.ManyToManyField("self")

- Django模型 数据操作初始化

  • 1 from django.db import models

  • 2 3 # Create your models here. 4 class Place(models.Model):

5

"""

6 位置信息

7 """

8 name = models.CharField(max_length=32,verbose_name= ' 地名 ')

9 address =

models.CharField(max_length=64,null=True,ver ' ' bose_name= 地址 )

10

11 class Meta: 12 db_table='t_place'

  • 13 14 class Restaurant(models.Model):

  • """

  • 15 16 餐厅 17 """ 18 name = models.CharField(max_length=32,verbose_name= ' 餐厅名 ')

  • 19 place = models.OneToOneField(Place,on_delete=models. ' '

  • CASCADE,verbose_name= 所在位置 ,null=True)

  • 20 21 class Meta: 22 db_table='t_restaurant' 23 24 class Waiter(models.Model): """

  • 25 26 服务员 27 """

28 name = models.CharField(max_length=32,verbose_name= ' 人名 ') 29 induction = ' models.DateTimeField(verbose_name= 入职时 ' 间 ,null=True) 30 restaurant = models.ForeignKey(Restaurant,on_delete=mode ' ' ls.CASCADE,verbose_name= 所在餐厅 ,null=True)

31 32 class Meta: 33 db_table='t_waiter' 34 35 class Food(models.Model): """ 36 37 食物 38 """ 39 name = models.CharField(max_length=32,verbose_name= ' 菜名 ') 40 is_main = models.BooleanField(default=True,verbose_nam ' ' e= 是否是主食 ,null=True)

41 restaurant = models.ManyToManyField(Restaurant,verbose_na ' ' me= 哪个餐厅有 ,null=True)

42 class Meta: 43 db_table='t_food' 44

Django Shell

除了运行程序时,可以测试模型,还可以在根目录的cmd执行:

1 python manage.py shell

打开django脚本控制台,测试执行模型的方法,会比启动项目更方 便

- Django模型 数据的添加

普通数据添加

Model.objects.create(filed)

obj.save()

  • 1 # 运行之前导入模块

  • 2 from more_app.models import # 其中 moremore_app 是子应用名

  • " "

  • 3 p = Person.objects.create(first_name= 刘 , " "

  • =

  • last_name 备 )

  • 4 # 或

  • 5 p1 = Person(first_name="Bruce", =

  • last_name "Springsteen")

  • 6 p1.save()

  • 1 from food_app.models import

  • 2 # 单表添加

  • "

  • 3 p1 = Place.objects.create(name= 北 " " "

  • 京 ,address= 中华大街 )

  • " " " "

  • 4 p2 = Place(name= 保定 ,address= 中心大街 )

  • 5 p2.save()

  • 6

  • 7 # 1 对 1 添加

  • 8 # 方法 1

  • "

  • 9 r1 = Restaurant.objects.create(name= 肯德 " =

  • 基 ,place p1)

  • 10 # 方法 2

  • " "

  • 11 r2 = Restaurant(name= 麦当劳 )

  • 12 r2.place=p2

  • 13 r2.save()

  • 14

  • 15 # 1 对多添加

  • 16 # 方法 1

  • "

  • 17 w2 = Waiter.objects.create(name= 吕小 "

  • 布 ,induction="2030-6-6",restaurant=r1)

18 # 方法 2 " " 19 w3 = Waiter(name= 貂蝉 ,induction="2030-6-6")

20 w3.restaurant=r2 21 w3.save() 22 23 # 多对多添加 " " 24 f1 = Food.objects.create(name= 鸡腿汉堡 ) 25 f1.restaurant.set([1,2])

提示

多对多添加数据关系,不能使用属性名,需要使用: 属性 名.set(),不然会报错如下:

TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use

restaurant.set() instead.

- Django模型 数据的查询介绍

查询方式

  • Model.objects.get( ) 返回一个匹配的对象

  • Model.objects.all( ) 返回一个 QuerySet ,包含所有数据

  • Model.objects.filter( ) 返回一个新的 QuerySet ,包含复合规则的

  • Model.objects.exclude( ) 返回一个新的 QuerySet ,不包含指定规则的

提示

通常与 QuerySet 交互时,会通过 链式过滤器 来使用它。为了实 现这一目的,大多数 QuerySet 方法都会返回新的查询集

代码

  • 1 # get 获取一个对象 2 # 查询主键等于 1 的 , 如果主键是 ID ,也可以使用 id=1

  • 3 # 如果条件找不到对应的记录,会抛出 DoesNotExist 错 误

4 #如果条件找到多个记录,会抛出
MultipleObjectsReturned错误
5 w1 = Waiter.objects.get(id=3)
6 w2 = Waiter.objects.get(pk=3)
7
8 # all获取所有对象
9 #查询所有,得到的QuerySets对象
10 w3 = Waiter.objects.all()
11 #过滤使用filter,复合指定条件的
12 w4 = Waiter.objects.filter(induction=”2030-
6-6”)
13 #过滤使用exclude,不复合指定条件的
14 w5 = Waiter.objects.exclude(induction=”2030-
6-6”)
15 # Queryset链式编程
16 w6 = Waiter.objects.filter(induction=”2030-
6-6”).filter(name=’吕布’)

注意

pk是主键的别名(primary key),如果真实主键是id,那么 pk 和 id 使用是一样的效果

- Django模型 数据的条件查询

常用检索字段

字段检索,是在字段名后加 ‘__’ 双下划线,再加关键字,类似 SQL 语句中的 where 后面的部分, 如: 字段名__关键字

exact :判断是否等于value,一般不使用,而直接使用 ‘=’

contains:是否包含,大小写敏感,如果需要不敏感的话,使用icontains

startswith:以value开头,大小写敏感

endwith:以value结尾,大小写敏感

  • in:是否包含在范围内

isnull:是否为null, 如:filter(name__isnull=Flase)

gt:大于,如:filter(sage__gt=30) , 年龄大于30

gte:大于等于

lt:小于

lte:小于等于

注意

在查找中指定的字段必须是模型字段的名称

但有一个例外,如果是ForeignKey字段,则是 属性名 或者 属性 名+ _id

1 #获取ID等于6
2 Waiter.objects.filter(id__exact=6)
3 #获取ID等于6
4 Waiter.objects.filter(id=6)
5 #获取name名字包含”张”
6 Waiter.objects.filter(name__contains=”张”)
7 #获取name名字包含”吕”
8 Waiter.objects.filter(name__contains=”吕”)
9 #获取name名字以”袁”开头的
10 Waiter.objects.filter(name__startswith=”袁”)
11 #获取name名字以”辽”结尾的
12 Waiter.objects.filter(name__endswith=”辽”)
13 #获取name名字是”关羽和黄忠”的
14 Waiter.objects.filter(name__in=[“关羽”,”黄
忠”])
15 #获取name名字为空的
16 Waiter.objects.filter(name__isnull=True)
17 #获取id大于5的
18 Waiter.objects.filter(id__gt=5)
19 #获取id小于5的
20 Waiter.objects.filter(id__lt=5)
21 #获取id小于等于5的
22 Waiter.objects.filter(id__lte=5)
23 #获取在id为1的餐厅工作的
24 Waiter.objects.filter(restaurant=1)
25 #获取在id为1的餐厅工作的
26 Waiter.objects.filter(restaurant_id=1)
27 #获取在name为肯德基的餐厅工作的
28 Waiter.objects.filter(restaurant__name=”肯德
基”)
29 #会报错,没有用俩个下划线!!!
30 Waiter.objects.filter(restaurant_name=”肯德
基”)

- Django模型 数据的时间查询

year/month/day/week_day/hour/minute/second:时间查询, 如: filter(induction__year=2030) 年份是2030的, filter(pub_date__day=15) 天数是15的

  • 1 from food_app.models import Waiter

  • 2 # 获取 2030.6.1 号入职的人,会警告时间类型

  • 3 Waiter.objects.filter(induction="2030-6-1 00:00:00")

  • 4 # 获取 2030.6.1 号入职的人

  • 5 Waiter.objects.filter(induction__date="20306-1")

  • 6 # 获取 2030.6.6 号之前入职的人

  • 7 Waiter.objects.filter(induction__lt="2030-66")

  • 8 # 获取 2030.6.2 到 2030.6.6 号之间入职的人

  • 9 Waiter.objects.filter(induction__range= ("2030-6-2","2030-6-6"))

  • 10 Waiter.objects.filter(induction__date__range =("2030-6-2","2030-6-6"))

  • 11 # 获取 2030 年入职的人 12 Waiter.objects.filter(induction__year=2030) 13 # 获取 6 月入职的人 14 Waiter.objects.filter(induction__month=6) 15 # 获取 6 号入职的人 16 Waiter.objects.filter(induction__day=6) 17 # 获取周 1 入职的人 18 Waiter.objects.filter(induction__week_day=1) 19 # 获取周日入职的人 20 Waiter.objects.filter(induction__week_day=7) 21 # 获取 2030 年 6 号,入职的人 22 Waiter.objects.filter(induction__year=2030,i nduction__day=6)

  • 23 Waiter.objects.filter(induction__year=2030). filter(induction__day=6)

  • 24 # 获取前 5 条入职的人 25 Waiter.objects.all()[:5] 26 # 获取第 6 到 11 条入职的人 27 Waiter.objects.all()[6:11] 28 # 不支持 29 Waiter.objects.all()[-1]

- Django模型 其它查询

排序

Queryset.order_by(*fields)

默认情况下, QuerySet 返回的结果是按照模型 Meta 中的 ordering 选项 给出的排序元组排序的

可以通过使用 order_by 方法在每个 QuerySet 的基础上覆盖这一点

1 class Meta:

2 ordering = ['name']

举例:

  • 1 Waiter.objects.filter(induction__year=2030).o rder_by('-induction','id')

上述结果将按 induction 降序排列,然后按 id 升序排列。 “-induction” 前 面的负号表示 降序。升序是隐含的

其它查询

reverse() 反向返回查询集元素的顺序

  • count() 返回一个整数,表示数据库中与 QuerySet 匹配的对象数量

  • first() 返回的是查询集中的第一个对象

  • last() 返回的是查询集中的最后一个对象

values()

  • 返回一个 QuerySet ,当用作可迭代对象时,返回字典,而不是模型实例, 其中每一个字典都 代表一个对象,键与模型对象的属性名相对应

  • values() 方法接受可选的位置参数 *fields ,它指定了 SELECT 应该被限制的字段名

  • 1 from food_app.models import Waiter 2 # 获取所有数据 3 Waiter.objects.all() 4 # 获取所有数据,按 id 排序,升序 5 Waiter.objects.all().order_by('id') 6 # 获取所有数据,按 id 排序,降序 7 Waiter.objects.all().order_by('-id') 8 # 获取所有数据,按 id 排序,升序,反序 9 Waiter.objects.all().order_by('id').reverse( )

  • 10 # 获取所有数据,按 induction 排序,升序 11 Waiter.objects.all().order_by('induction')

  • 12 # 获取 2030-6-7 之前入职的数据,按 induction 排序升 序,若值相同按 id 排序降序

  • 13 Waiter.objects.filter(induction__lt='2030-67').order_by('induction','-id') # 获取 2030-67 之前入职的数据,统计数量

  • 14 Waiter.objects.filter(induction__lt='2030-67').count()

  • 15 # 获取 2030-6-7 之前入职的数据,获取第 1 条 16 Waiter.objects.filter(induction__lt='2030-67').first()

  • 17 # 获取 2030-6-7 之前入职的数据,获取最后 1 条 18 Waiter.objects.filter(induction__lt='2030-67').last()

  • 19 # 获取 2030-6-7 之前入职的数据,将数据转成 dict 放在 QuerySet 中

  • 20 Waiter.objects.filter(induction__lt='2030-67').values()

  • 21 # 获取 2030-6-7 之前入职的数据,将数据转成 dict ,只要 id 与 name 字段,放在 QuerySet 中

  • 22 Waiter.objects.filter(induction__lt='2030-67').values('id','name')

注意

大部分检索是懒惰执行的,只在真实获取值的时候,才会去连 接数据库获取数据

  • 1 # 还没获取数据

  • 2 w1 =

Waiter.objects.filter(induction__lt='2030-67').values('id','name')

  • 3 # 获取数据

  • 4 print(w1)

  • 5 # 获取数据,因为要做数据切片

  • 6 w1 =

Waiter.objects.filter(induction__lt='2030-67').values('id','name')[:2]

- Django模型 数据关联查询

一对一关系

  • 1 class Place(models.Model): 2 name = models.CharField(max_length=50) 3 address = models.CharField(max_length=80)

4

  • 5 class Restaurant(models.Model):

  • """

  • 6

  • 7 餐厅 8 """

9 name = models.CharField(max_length=32,verbose_name= ' 餐厅名 ')

10 place = models.OneToOneField(Place,on_delete=models. ' ' CASCADE,verbose_name= 所在位置 ,null=True)

11 12 class Meta: 13 db_table='t_restaurant'

  • 14

15 16 # 通过 Place 查找 Restaurant

17 place = Place.objects.first()

  • 18 restaurant = place.restaurant

19

  • 20 # 通过 定义了 OneToOneField 的模型 Restaurant 查找 Place

  • 21 restaurant = Restaurant.objects.first() 22 place = restaurant.place

一对多关系

  • 1 from django.db import models

  • 2

  • 3 class Restaurant(models.Model):

  • """

  • 4

  • 5 餐厅 6 """ 7 name = models.CharField(max_length=32,verbose_name= ' 餐厅名 ')

8 place = models.OneToOneField(Place,on_delete=models. ' ' CASCADE,verbose_name= 所在位置 ,null=True)

9 10 class Meta: 11 db_table='t_restaurant'

  • 12 13 class Waiter(models.Model): """

  • 14 15 服务员 16 """ 17 name = models.CharField(max_length=32,verbose_name= ' 人名 ')

18 induction =

' models.DateTimeField(verbose_name= 入职时 ' 间 ,null=True)

19 restaurant =

models.ForeignKey(Restaurant,on_delete=mode ' ' ls.CASCADE,verbose_name= 所在餐厅 ,null=True)

20 def __str__(self):

21 return f'{self.name} == ' {self.induction}

22 class Meta: 23 db_table='t_waiter'

24

25 # 从 一的模型 查找 多的模型

26 # 通过 ' 多的模型小写名 _set' 查找 27 restaurant = Restaurant.objects.first()

  • 28 waiters = restaurant.waiter_set.all()

29

30 # 从 多的模型 查找 一的模型

31 w1 = Waiter.objects.first() 32 r1 = w1.restaurant

多对多关系

  • 1 from django.db import models

  • 2 3 class Restaurant(models.Model):

""" 4

5 餐厅 6 """ 7 name = models.CharField(max_length=32,verbose_name= ' 餐厅名 ')

8 place =

models.OneToOneField(Place,on_delete=models. ' ' CASCADE,verbose_name= 所在位置 ,null=True)

9

10 class Meta:

11 db_table='t_restaurant'

12 13 class Food(models.Model): """ 14 15 食物 16 """ 17 name = models.CharField(max_length=32,verbose_name= ' 菜名 ') 18 is_main = models.BooleanField(default=True,verbose_nam ' ' e= 是否是主食 ,null=True) 19 restaurant = models.ManyToManyField(Restaurant,verbose_na ' ' me= 哪个餐厅有 ,null=True) 20 class Meta: 21 db_table='t_food' 22 23 # 从 没有写 ManyToManyField 的模型查找另一 写了 ManyToManyField 的模型 24 # 需要在 查询的模型名的小写后 加 _set 25 restaurant = Restaurant.objects.first() 26 foods = Restaurant.food_set.all() 27 28 # 从 写了 ManyToManyField 的模型查找另一个模型 29 food = Food.objects.first() 30 schoolClasses = food.restaurant.all()

- Django模型 聚合与分组查询

准备数据

1 class Cook(models.Model): """ 2 3 厨师 4 """ 5 name = models.CharField(max_length=32,verbose_name= ' 厨师名 ') 6 level = ' ' models.IntegerField(verbose_name= 厨艺等级 ) 7 age = ' ' models.IntegerField(verbose_name= 年龄 ) 8 sect = models.CharField(max_length=32,verbose_name= ' 厨艺派系 ') 9 class Meta: 10 db_table='t_cook'

  • 1 insert into t_cook (name,level,age,sect) values (" 黑暗之女 ",6,20," 川菜 ");

  • 2 insert into t_cook (name,level,age,sect) values (" 狂战士 ",5,24," 粤菜 ");

  • 3 insert into t_cook (name,level,age,sect) values (" 卡牌大师 ",6,25," 川菜 ");

  • 4 insert into t_cook (name,level,age,sect) values (" 德邦总管 ",6,26," 鲁菜 ");

  • 5 insert into t_cook (name,level,age,sect) values (" 无畏战车 ",3,24," 湘菜 ");

  • 6 insert into t_cook (name,level,age,sect) values (" 诡术妖姬 ",6,22," 川菜 ");

7 insert intot_cook(name,level,age,sect)
values (“猩红收割者”,2,21,”鲁菜”);
8 insert intot_cook(name,level,age,sect)
values (“远古恐惧”,4,20,”湘菜”);
9 insert intot_cook(name,level,age,sect)
values (“正义天使”,6,21,”川菜”);
10 insert intot_cook(name,level,age,sect)
values (“无极剑圣”,2,20,”粤菜”);
11 insert intot_cook(name,level,age,sect)
values (“牛头酋长”,6,25,”湘菜”);
12 insert intot_cook(name,level,age,sect)
values (“符文法师”,1,26,”川菜”);
13 insert intot_cook(name,level,age,sect)
values (“亡灵战神”,6,30,”鲁菜”);
14 insert intot_cook(name,level,age,sect)
values (“战争女神”,1,18,”川菜”);
15 insert intot_cook(name,level,age,sect)
values (“众星之子”,6,20,”湘菜”);
16 insert intot_cook(name,level,age,sect)
values (“迅捷斥候”,6,20,”川菜”);
17 insert intot_cook(name,level,age,sect)
values (“麦林炮手”,6,15,”粤菜”);
18 insert intot_cook(name,level,age,sect)
values (“祖安怒兽”,2,29,”粤菜”);
19 insert intot_cook(name,level,age,sect)
values (“赏金猎人”,6,22,”川菜”);
20 insert intot_cook(name,level,age,sect)
values (“寒冰射手”,4,18,”鲁菜”);

聚合函数

对数据表计算统计值,需要使用 aggregate 方法,提供的参数可以 是一个或者多个聚合函数,aggregate 是 QuerySet 的一个子句, 它的返回值是一个字典类型

常用的聚合函数有:Avg、Count、Max、Min、Sum

  • 1 # Max 找出最大的

  • 2 from django.db.models import Max 3 Cook.objects.aggregate(Max('age'))

  • 4 # 结果是一个字典 {'age__max': 30}

  • 5 # 可以使用 max=Max('age') 指定 别名为 max ,而不使 用 age__max

  • 6 Cook.objects.aggregate(max=Max('age'))

  • 7

  • 8 # 多个聚合函数一起使用

  • 9 Cook.objects.aggregate(Max('age'), Min('age'), Avg('age'))

分组查询

使用annotate()函数实现分组查询,得配合其他函数:

  • annotate:用于分组,配合 Avg,Count等聚合函数,如:annotate(max=Max(‘age’))

  • filter: 用于过滤,在 annotate之前使用表示 where 条件,在annotate之后使用表示having条件

  • values:在annotate之前使用表示分组字段,在annotate之后使用表示取值

1 # 基本应用

  • 2 # 以 group_id 分组,找出 level 的最大值,最小值,和平 均值

  • 3 Cook.objects.values('sect').annotate(max=Max( 'level'), min=Min('level'), avg=Avg('level'))

4

  • 5 # 以 group_id 分组 并且 group_id 大于 2 ,找出 level 的最大值,最小值,和平均值

  • 6 Cook.objects.values('sect').annotate(max=Max( 'level'), min=Min('level'),

    • ' '

    • avg=Avg('level')).filter(sect= 鲁菜 )

  • 7 # 和下面这句等效

  • 8 # 推荐使用下面这种方式

  • '

  • 9 Cook.objects.filter(sect= 鲁

    • '

    • 菜 ).values('sect').annotate(max=Max('level') , min=Min('level'), avg=Avg('level'))

- Django模型 修改数据

  • 1 先获取对象,通过对象属性更新数据,再保存 (更新单一数据)

  • 2 通过QuerySet的update函数更新数据 (更新多条数据)

  • 1 # 单条记录修改 save 2 c = Cook.objects.get(pk=1) ' '

  • 3 c.name = 安妮 4 c.save() 5 6 # 更新多个值 update '

  • 7 Cook.objects.filter(sect= 粤 '

  • 菜 ).update(level=5)

- Django模型 刷新对象

通过 refresh_from_db 从数据库中重新获取对象的内容

  • 1 c = Cook.objects.get(pk=1) 2 c.refresh_from_db()

- Django模型 删除数据

  • 1 先获取对象,通过对象调用delete函数 (删除单一数据)

  • 2 通过QuerySet的delete函数 (删除多条数据)

  • 1 c = Cook.objects.get(pk=1)

  • 2 c.delete()

  • 3

  • 4 Cook.objects.filter(level=3).delete()

提示

在真实项目中,往往不会真的删除数据,而选择使用逻辑删 除!

- Django模型 Q对象

filter() 等方法中的关键字参数查询都是并且(‘AND’)的, 如果需要执 行更复杂的查询(例如or语句),那么可以使用 django.db.models.Q 对 象。

Q 对象 (django.db.models.Q) 对象用于封装一组关键字参数,可以 使用 & 和 | 操作符组合起来,当一个操作符在两个Q 对象上使用 时,它产生一个新的Q 对象。

注意

  • Q对象可以和一般的关键字参数混用, 但是Q对象必须在一般关键字参数的前面

  • Q对象可以多个同时使用

  • ~

  • Q对象前面可以增加 用于取反

1 from food_app.models import Cook
2 #查询等级为5的数据
3 Cook.objects.filter(level=5)
4 #查询等级为5,并且派系为川菜的数据
5 Cook.objects.filter(level=5,sect=”川菜”)
6 #查询等级为5,并且派系为川菜的数据
7 Cook.objects.filter(level=5).filter(sect=”川
菜”)
8 #查询等级为6,或者派系为湘菜的数据,不支持这个写
法!!!
9 Cook.objects.filter(level=6 or sect=”湘菜”)
10 #查询等级为6,或者派系为湘菜的数据,不支持这个写
法!!!
11 Cook.objects.filter(level=6
12
13 from django.db.models import Q
14 #查询等级为6,或者派系为湘菜的数据
15 Cook.objects.filter(Q(level=6)
菜”))
16 #查询等级为6,并且派系为湘菜的数据
17 Cook.objects.filter(level=6,sect=”湘菜”)
18 #查询等级4,并且等级为6,或者派系为湘菜的数据
19 Cook.objects.filter(Q(id=4),Q(level=6)
Q(sect=”湘菜”))
20 #查询等级不为4,并且等级为6,或者派系为湘菜的数据
21 Cook.objects.filter(~Q(id=4),Q(level=6)
Q(sect=”湘菜”))
22 #查询等级4,并且等级为6,或者派系为湘菜的数据
23 Cook.objects.filter(Q(level=6)
菜”),id=4)
24 #查询等级4,并且等级为6,或者派系为湘菜的数据,不支
持这个写法!!!

Cook.objects.filter(id=4,Q(level=6) | " " Q(sect= 湘菜 ))

25

Django模型-F对象

作用:模型的属性名出现在操作符的右边,就使用F对象进行包裹

数据初始化

模型

1 class Salary(models.Model): """ 2 3 薪资组成 4 """ 5 name = models.CharField(max_length=32,verbose_name= ' 员工名 ') 6 basic = ' ' models.IntegerField(verbose_name= 底薪 ) 7 seniority = ' ' models.IntegerField(verbose_name= 工龄 ) 8 outstand = ' ' models.IntegerField(verbose_name= 优秀次数 ) 9 class Meta: 10 db_table='t_salary'

数据

1 insert intot_salary
(name,basic,seniority,outstand) values (‘安
柏’,4000,1,0);
2 insert intot_salary
(name,basic,seniority,outstand) values (‘凯
亚’,2000,0,5);
3 insert intot_salary
(name,basic,seniority,outstand) values (‘丽
莎’,4000,1,0);
4 insert intot_salary
(name,basic,seniority,outstand) values (‘芭芭
拉’,3000,3,5);
5 insert intot_salary
(name,basic,seniority,outstand) values (‘雷
泽’,6000,2,0);
6 insert intot_salary
(name,basic,seniority,outstand) values (‘菲谢
尔’,5000,3,6);
7 insert intot_salary
(name,basic,seniority,outstand) values (‘班尼
特’,5000,2,0);
8 insert intot_salary
(name,basic,seniority,outstand) values (‘诺艾
尔’,3000,3,3);
9 insert intot_salary
(name,basic,seniority,outstand) values (‘砂
糖’,4000,3,0);
10 insert intot_salary
(name,basic,seniority,outstand) values
(‘琴’,7000,5,6);
11 insert intot_salary
(name,basic,seniority,outstand) values (‘迪卢
克’,8000,3,5);
12 insert intot_salary
(name,basic,seniority,outstand) values (‘莫
娜’,6000,3,0);
13 insert intot_salary
(name,basic,seniority,outstand) values (‘温
迪’,7000,5,3);
14 insert intot_salary
(name,basic,seniority,outstand) values (‘可
莉’,8000,3,6);

15 insert into t_salary

  • (name,basic,seniority,outstand) values (' 迪奥 娜 ',9000,5,0);

16 insert into t_salary (name,basic,seniority,outstand) values (' 阿贝 多 ',6000,3,3);

17 insert into t_salary (name,basic,seniority,outstand) values (' 优 菈 ',5000,5,6);

18 insert into t_salary (name,basic,seniority,outstand) values (' 罗莎 莉亚 ',5000,3,3);

可以使用模型的A属性与B属性进行比较

  • 1 # 获取工龄等于优秀表现次数的员工 2 Salary.objects.filter(seniority=F("outstan d"))

支持算数运算

  • 1 # 获取平均每年大于 1 次的员工

  • 2 Salary.objects.filter(outstand__gt=F("seni ority")+1)

  • 3 # 更新员工工作年限 +1 4 Salary.objects.update(seniority=F('seniori ty')+1)

  • 1 # urlconf 中 2 urlpatterns = [ 3 path('fbv/', views.current_datetime), 4 ] 5 6 # views 中 7 from django.http import HttpResponse 8 import datetime 9

  • 10 def current_datetime(request): 11 now = datetime.datetime.now() 12 html = "<html><body>It is now %s.</body> </html>" % now

  • 13 return HttpResponse(html)

笔记

  • 视图函数 current_datetime,每个视图函数都将一个HttpRequest 对象作为其第一个参数, 该参数通常被命名request

  • 视图函数的名称无关紧要,它不必以某种方式命名,以便Django能够识别它,但是函数命名 一定要能够清晰的描述它的功能

  • 视图函数返回一个HttpResponse响应的对象,每个视图函数负责返回一个HttpResponse对 象(有例外,但我们在稍后讨论)

CBV

就是在视图里使用类处理请求

  • 1 # urlconf 中 2 urlpatterns = [ 3 # 一定要使用 as_view() ,记住 小括号 4 path('cbv/', views.MyView.as_view()), 5 ] 6

  • 7 # views 中 8 from django.http import HttpResponse 9 from django.views import View

  • 10

  • 11 class MyView(View): 12 13 def get(self, request): 14 return HttpResponse('get OK') 15 16 def post(self, request): 17 return HttpResponse('post OK')

笔记

  • CBV提供了一个as_view()静态方法(也就是类方法),调用这个方法,会创建一个类的实 例,然后通过实例调用dispatch()方法,dispatch()方法会根据request的method的不同调用 相应的方法来处理request(如get(),post()等)

  • 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)

  • 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多 if 判断,可以提高代码可读性

- Django视图 返回错误响应

返回错误的3种方式:

  • 返回 HttpResponseNotFound

  • 返回 HttpResponse 设置 status 状态码

  • 返回 Http404状态对象

  • 1 # 使用 HttpResponseNotFound

  • 2 def my_view(request):

  • 3 return HttpResponseNotFound('<h1>Page not found</h1>')

4

  • 5 # 还可以直接返回状态码

  • 6 from django.http import HttpResponse

  • 7 def my_view(request):

  • 8 return HttpResponse(status=201)

  • 9

  • 10 # 特殊的 404 错误

  • 11 from django.http import Http404

  • 12 from django.shortcuts import render

  • 13 14 def detail(request, poll_id): 15 raise Http404("Model does not exist") 16 return HttpResponse('<h1>Page was found</h1>')

- Django视图 视图装饰器

@require_http_methods,要求视图只接收指定的http方法

@require_GET():仅仅允许GET方法

@require_POST():仅仅允许POST方法

@require_safe():仅仅允许GET和HEAD方法

1 from django.views.decorators.http import require_http_methods

2

  • 3 # 允许 GET 和 POST 方法, 默认就是所有方法都支持 4 @require_http_methods(["GET", "POST"])

  • 5 def my_view(request): 6 # I can assume now that only GET or POST requests make it this far

7 # ...

  • 8 pass

9

@login_required

必须登录才能访问装饰的视图函数,

用户未登录,则重定向到settings.LOGIN_URL,除非指定了 login_url参数,例如:@login_required(login_url=’/polls/login/‘)

  • 1 @login_required

  • 2 def my_view(request): 3 # I can assume now that only GET or POST requests make it this far

  • 4 # ... 5 pass

- Django视图 请求对象HttpRequest

每一个用户请求在到达视图函数的同时,Django 会创建一个 HttpRequest对象并把这个对象当做第一个参数传给要调用的views 方法。HttpRequest对象包含了请求的元数据,比如(本次请求所涉及 的用户浏览器端数据、服务器端数据等),在views里可以通过 request对象来调用相应的属性

所有视图函数的第一个参数都是HttpRequest实例

属性(除非另有说明,否则所有属性均应视为只读):

: HttpRequest.scheme

表示请求使用的协议(http或https)

: HttpRequest.body

原始HTTP请求主体,类型是字节串。处理数据一些非html表单 的数据类型很有用,譬如:二进制图像,XML等;

  • 取form表单数据,请使用 HttpRequest.POST

  • 取url中的参数,用HttpRequest.GET

: HttpRequest.path

表示请求页面的完整路径的字符串,不包括scheme和域名。

例: “/music/bands/the_beatles/“

: HttpRequest.method

表示请求中使用的HTTP方法的字符串,是大写的。例如:

  • 1 if request.method == 'GET': 2 do_something() 3 elif request.method == 'POST': 4 do_something_else()

: HttpRequest.encoding

表示当前编码的字符串,用于解码表单提交数据(或者None,

表示使用该DEFAULT_CHARSET设置)。

可以设置此属性来更改访问表单数据时使用的编码,修改后,后 续的属性访问(例如读取GET或POST)将使用新encoding值。

HttpRequest.content_type:

表示请求的MIME类型的字符串,从CONTENT_TYPE解析 。

HttpRequest.content_params:

包含在CONTENT_TYPE 标题中的键/值参数字典。

HttpRequest.GET:

包含所有给定的HTTP GET参数的类似字典的对象。请参阅 QueryDict下面的文档。

HttpRequest.POST:

包含所有给定HTTP POST参数的类似字典的对象,前提是请求 包含表单数据。请参阅QueryDict文档。POST不包含文件信 息,文件信息请见FILES。

HttpRequest.COOKIES:

包含所有Cookie的字典,键和值是字符串。

HttpRequest.FILES:

包含所有上传文件的类似字典的对象

HttpRequest.META:

包含所有可用HTTP meta的字典

中间件设置的属性:

Django的contrib应用程序中包含的一些中间件在请求中设置了属 性。如果在请求中看不到该属性,请确保使用了相应的中间件类 MIDDLEWARE

HttpRequest.session:

来自SessionMiddleware:代表当前会话的可读写字典对象。

  • HttpRequest.site:

来自CurrentSiteMiddleware: 代表当前网站的实例Site或 RequestSite返回get_current_site()

  • HttpRequest.user:

来自AuthenticationMiddleware:AUTH_USER_MODEL代表当 前登录用户的实例

- Django视图 QueryDict

在一个 HttpRequest 对象中, GET 和 POST属性是 django.http.QueryDict 的实例,这是一个类似字典的类

获取单个数据

queryDict.get(key)

queryDict[key]

注意

如果键有多个值,获取的值为最后一个值

获取多个数据

queryDict.getlist(key)

获取key与value

list(queryDict.items())

注意

如果键有多个值,获取的值为最后一个值

  • 1 from django.http import HttpResponse 2
2
3 def query_index(request):
4 #获取参数
5 params = request.GET
6 #打印params类型
7 print(type(params))# <class
‘django.http.request.QueryDict’>
8 #获取单个值
9 s_value1 = params.get(‘a’)#推荐
10 s_value2 = params[‘a’]#如果没有值,会报
11 s_value3 = params.get(‘c’)
12 #获取多个值
13 m_value = params.getlist(‘c’)
14 #同时获取key与value
15 kv_value = list(params.items())
16 #返回结果

17

return HttpResponse(f'request.GET:

{params}<br/> 类型是 :{type(params)}

<br/>s_value1:{s_value1}<br/>s_value2:

{s_value2}<br/> s_value3:{s_value3} <br/> m_value:{m_value}<br/>kv_value:{kv_value}')

18

Django响应-HttpResponse与JsonResponse

==> picture [19 x 10] intentionally omitted <==

—– Start of picture text —–

120
—– End of picture text —–

HttpResponse

返回给浏览器端的响应对象

  • 1 from django.http import HttpResponse

  • 2 response = HttpResponse("Here's the text of the web page.")

  • 3 response = HttpResponse("Text only, please.", =

  • content_type "text/plain")

  • 4 response = HttpResponse(b'Bytestrings are also accepted.')

属性

  • HttpResponse.content: 表示响应的字符串

  • HttpResponse.charset:

  • 表示响应将被编码的字符集,如果在HttpResponse实例化时没 有给出,则会从中提取 content_type,如果没有设置

content_type,则使用settings.DEFAULT_CHARSET

  • HttpResponse.status_code:

  • 该响应的 HTTP 状态码

HttpResponse.reason_phrase:

响应的HTTP原因描述语,使用HTTP标准的默认原因描述语 除非明确设置,否则reason_phrase由 status_code 决定。

  • HttpResponse.streaming:

总是False,中间件通过此属性可以区分流式响应与常规响应

  • HttpResponse.closed:

如果response已经结束,则返回True,否则返回False

JsonResponse

包含json格式内容的响应

  • 1 from django.http import JsonResponse 2

  • 3 response = JsonResponse({'foo': 'bar'}) 4 print(response.content) # 打印 b'{"foo":

    • "bar"}'

Django响应-FileResponse

返回文件内容的响应

  • 1 import os

  • 2 from django.conf import settings

  • 3 from django.http import FileResponse

  • 4

  • 5 def resp_file(request): 6 file_path = os.path.join(settings.BASE_DIR,'imgs/tu1.png' )

  • 7 return FileResponse(open(file_path,'rb'),filename='t u1.png')

- Django响应 返回模板

render方法

e 1 必需的参数

request:用于生成此响应的请求对象

template_name:要使用的模板的全名或模板名称的列表

2 _ 可选参数

  • context:要添加到模板上下文的值的字典。默认情况下,这是一个空字典。如果字典中的值 是可调用的,视图将在渲染模板之前调用它

  • content_type:用于生成文档的MIME类型。默认为DEFAULT_CONTENT_TYPE设置的值

  • status:响应的状态码。默认为200

  • using:用于加载模板的模板引擎名

方法

  • 1 from django.shortcuts import render

  • 2

  • 3 def my_view(request): 4 return render( 5 request, 6 'myapp/index.html', 7 {'foo': 'bar'}, 8 content_type='application/xhtml+xml' 9 )

loader方法

  • 1 from django.http import HttpResponse 2 from django.template import loader 3 4 def my_view(request): 5 t = loader.get_template('myapp/index.html')

  • 6 c = {'foo': 'bar'} 7 return HttpResponse(t.render(c, request), =

  • content_type 'application/xhtml+xml')

- Django响应 重定向

==> picture [91 x 15] intentionally omitted <==

—– Start of picture text —–

生活中的案例
—– End of picture text —–

django.shortcuts.redirect 方法

e 1 重定向新地址 1 from django.shortcuts import redirect 2 3 def my_view(request): 4 5 return redirect('https://www.itbaizhan.com/')

@ 2 通过传递硬编码的URL重定向:

  • 1 def my_view(request): 2 return redirect('/some/url/')

  • rd] 3 通过传递一个URLConf调度器中配置path或re_path的名称,以 及可选的一些位置或关键字参数,该URL将使用reverse()方法反 向解析 :

    • 1 def my_view(request): 2 return redirect('polls:index', foo='bar')
  • e 4 默认情况下,redirect()返回一个临时重定向(302)。 如果要设置永久重定向(301)设置permanent参数;为True即 可:

    • 1 def my_view(request): 2 return redirect('polls:index', permanent=True)

- Django响应 查找不到返回404

数据初始化

1 class Salary(models.Model): """ 2 3 薪资组成 4 """ 5 name = models.CharField(max_length=32,verbose_name= ' 员工名 ') 6 basic = ' ' models.IntegerField(verbose_name= 底薪 ) 7 seniority = ' ' models.IntegerField(verbose_name= 工龄 )

  • 8 outstand = ' '

  • models.IntegerField(verbose_name= 优秀次数 )

  • 9 class Meta:

  • 10 db_table='t_salary'

必需的参数

klass:一Model类或一个Manager或QuerySet从哪个实例来获取对象

  • **kwargs:查找参数,应该采用get()或filter()的参数

  • 1 from django.shortcuts import get_object_or_404

2

  • 3 def my_view(request): 4 poll = get_object_or_404(Salary, pk=1)

5

  • 6 # 等同于

  • 7 def my_view(request): 8 try:

  • 9 poll = Salary.objects.get(pk=1)

  • 10 except Salary.DoesNotExist: 11 raise Http404()

- Django响应 内置通用视图

引入位置 from django.views import generic

1 __all__ = [ 2 'View', 'TemplateView', 'RedirectView', 'ArchiveIndexView', 3 'YearArchiveView', 'MonthArchiveView', 'WeekArchiveView', 'DayArchiveView', 4 'TodayArchiveView', 'DateDetailView', 'DetailView', 'FormView', 5 'CreateView', 'UpdateView', 'DeleteView', 'ListView', 'GenericViewError', 6 ] 7

比较常用的:DetailView、ListView

代码

  • 1 urlpatterns =[ 2

path('salary/<int:pk>/',MyDetailView1.as_vie w()),

3

path('salary2/<int:pk>/',MyDetailView2.as_vi ew()),

  • 4 path('salary3/',MyListView.as_view()), 5 ]

  • 1 from django.shortcuts import render

  • 2 from error_app.models import Salary

  • 3 # Create your views here.

  • 4 from django.views import generic

  • 5

  • 6 class MyDetailView1(generic.DetailView): 7 # 设置要返回哪个 model 的数据 8 model= Salary 9 # 设置让哪个模板渲染数据

  • 10 template_name='detail.html'

  • 11

  • 12 class MyDetailView2(generic.DetailView): 13 # 设置要返回哪个 model 的数据 14 queryset= Salary.objects.all() 15 # 设置让哪个模板渲染数据 16 template_name='detail.html' 17 18 class MyListView(generic.ListView): 19 # 设置要返回哪个 model 的数据

20 model= Salary

  • 21 # 设置让哪个模板渲染数据

22 template_name='list.html'

  • 1 # template(detail.html)

  • 2 {{object}}

  • 3 # template(list.tml)

  • 4 {{object_list}}

- Django模板 基本规则

作为一个Web框架,Django需要一种方便的方式来动态生成 HTML。最常用的方法依赖于模板。模板包含 所需HTML输出的静态 部分 以及描述如何插入 动态内容的特殊语法

django默认模板

在settings中配置:

  • 1 TEMPLATES = [ 2 { 3 'BACKEND':

'django.template.backends.django.DjangoTempl ates',

  • 4 'DIRS': [], 5 'APP_DIRS': True, 6 'OPTIONS': { 7 'context_processors': [

  • 8

'django.template.context_processors.debug',

9

'django.template.context_processors.request ' , 10 'django.contrib.auth.context_processors.aut h', 11 'django.contrib.messages.context_processors .messages', 12 ], 13 }, 14 }, 15 ]

属性介绍

  • BACKEND:是实现Django模板后端API的模板引擎类的路径。内置是 django.template.backends.django.DjangoTemplates和 django.template.backends.jinja2.Jinja2(使用这个需要额外安装jinja2库)

  • DIRS :按搜索顺序定义引擎应该查找模板源文件的目录列表

  • APP_DIRS:告诉引擎是否应该在已安装的应用程序中查找模板

  • OPTIONS:包含后端特定的设置

多引擎用法

假如settings中配置如下:

  • 1 TEMPLATES = [ 2 { 3 'BACKEND': 'django.template.backends.django.DjangoTempl ates',

  • 4 'DIRS': [ 5 '/home/html/example.com',

6 '/home/html/default', 7 ], 8 }, 9 { 10 'BACKEND': 'django.template.backends.jinja2.Jinja2', 11 'DIRS': [ 12 '/home/html/jinja2', 13 ], 14 }, 15 ]

  • e 1 django.template.loader.get_template 该函数使用给定名称加载模板并返回一个 Template对象,找到 第一个匹配的模板即返回

    • 1 template = get_template('story_detail.html')

Django将要查找的文件,依次为:

  • /home/html/example.com/story_detail.html(’django’引擎)

  • /home/html/default/story_detail.html(’django’引擎)

  • /home/html/jinja2/story_detail.html(’jinja2’引擎)

方法

  • 1 from django.shortcuts import render

  • 2 3 def my_view(request):

  • 4 return render( 5 request,

6 'myapp/index.html', 7 {'foo': 'bar'}, 8 = content_type 'application/xhtml+xml' 9 )

loader方法

1 from django.http import HttpResponse 2 from django.template import loader 3 4 def my_view(request): 5 t = loader.get_template('myapp/index.html') 6 c = {'foo': 'bar'} 7 return HttpResponse(t.render(c, request), = content_type 'application/xhtml+xml')

  • @ 2 django.template.loader.select_template

select_template() 用法类似 get_template() ,除了它需要一个 模板名称的列表。它按顺序尝试每个名称并返回存在的第一个模 板

1 template = select_template(['story_253_detail.html',' story_detail.html'])

Django将要查找的文件,依次为:

  • /home/html/example.com/story_253_detail.html(’django’引擎)

/home/html/default/story_253_detail.html(’django’引擎)

/home/html/jinja2/story_253_detail.html(’jinja2’引擎)

/home/html/example.com/story_detail.html(’django’引擎)

  • /home/html/default/story_detail.html(’django’引擎)

  • /home/html/jinja2/story_detail.html(’jinja2’引擎)

- Django模板 变量

模板是通过上下文来渲染的。渲染用变量的值替换变量,变量的值 在上下文中查找,并执行标签。其他的一切都按原样输出。

Django 模板语言的语法涉及四个构造

变量: 变量从上下文中输出一个值,上下文是一个类似于字典的对象,将键映射到值

标签: 标签在渲染过程中提供使用逻辑的方法,比如:if和for

过滤器: 过滤器转换变量和标签参数的值

Comments: 注释

变量

变量被这样包围 :{{变量}} ,如下所示:

  • 1 学的技术是 {{ first_name }}. 语言为 {{ last_name }}

在上下文为 {‘first_name’: ‘IT’, ‘last_name’: ‘Python’} 的情况下,该模板渲染为:

  • 1 我学的技术是 IT. 语言为 Python

字典查找,属性查找和列表索引查找均以点符号实现:

  • 1 {{ my_dict.key }}

  • 2 {{ my_object.attribute }}

  • 3 {{ my_list.0 }}

- Django模板 标签if

标签在渲染过程中提供使用逻辑的方法,比如:if和for

标签被 {% 和 %} 包围,如下所示:

由于在模板中,没有办法通过代码缩进判断代码块,所以控制标签 都需要有结束的标签

if

判断标签{% if %} {% endif %} :

1 # athlete_list 不为空 2 {% if athlete_list %} 3 # 输出 athlete_list 的长度 | 是过滤器 4 Number of athletes: {{ athlete_list|length }} 5 {% elif athlete_in_locker_room_list %} 6 Athletes should be out of the locker room soon! 7 {% else %} 8 No athletes. 9 {% endif %}

firstof

输出不是False的第一个参数,所有参数都为False,则什么都不 输出

1 {% firstof var1 var2 var3 %} 2 等同于 3 {% if var1 %} 4 {{ var1 }} 5 {% elif var2 %} 6 {{ var2 }} 7 {% elif var3 %} 8 {{ var3 }} 9 {% endif %} 10 11 使用默认值: " " 12 {% firstof var1 var2 var3 默认值 %}

逻辑运算符

and、or和not

1 {% if athlete_list and coach_list %} 2 Both athletes and coaches are available. 3 {% endif %} 4 5 {% if not athlete_list %} 6 There are no athletes. 7 {% endif %} 8 9 {% if athlete_list or coach_list %} 10 There are some athletes or some coaches.

  • 11 {% endif %} 12 13 {% if not athlete_list or coach_list %} 14 There are no athletes or there are some coaches.

15 {% endif %} 16

  • 17 {% if athlete_list and not coach_list %} 18 There are some athletes and absolutely no coaches.

19 {% endif %} 20

允许在同一个标签中使用两个and和or子句, and优先级高于or 例如:

  • 1 {% if athlete_list and coach_list or cheerleader_list %}

  • 2 将被解释为: 3 if (athlete_list and coach_list) or cheerleader_list

但是在if标签中使用实际的括号是无效的语法。如果你需要它们 来表示优先级,你应该使用嵌套if标签

比较运算符

==, !=, <, >, <=, >=, in, not in, is, 和 is not

1 {% if somevar == "x" %} 2 This appears if variable somevar equals the string "x" 3 {% endif %} 4 5 {% if "bc" in "abcdef" %} 6 This appears since "bc" is a substring of "abcdef" 7 {% endif %} 8 9 {% if somevar is not True %} 10 This appears if somevar is not True, or if somevar is not found in the 11 context. 12 {% endif %}

优先级,从低到高:

or and not in ==,!=,<,>,<=,>=

- Django模板 标签for

for

循环遍历,{% for %} {% endfor %} 结束 ,可以遍历列表,字典等

1 <ul> 2 {% for athlete in athlete_list %} 3 <li>{{ athlete.name }}</li> 4 {% endfor %}

5 </ul>

  • 6 7 反向循环: 8 {% for athlete in athlete_list reversed%} 9

  • 10 字典: data.items 这种调用方法,是不加 () 的 11 {% for key, value in data.items %} 12 {{ key }}: {{ value }} 13 {% endfor %} 14 15 设置默认值, for empty ,类似 python 的 for else :

  • 16 <ul> 17 {% for athlete in athlete_list %} 18 <li>{{ athlete.name }}</li> 19 {% empty %} 20 <li>Sorry, no athletes in this list. </li>

  • 21 {% endfor %} 22 </ul> 23 等同于,但是比下面的写法更加简便: 24 <ul> 25 {% if athlete_list %} 26 {% for athlete in athlete_list %} 27 <li>{{ athlete.name }}</li> 28 {% endfor %} 29 {% else %} 30 <li>Sorry, no athletes in this list. </li>

  • 31 {% endif %} 32 </ul>

33

for循环在循环中设置了许多变量:

变量名 描述
forloop.counter 循环计数器,表示当前循环的索引(从
1 开始)。
forloop.counter0 循环计数器,表示当前循环的索引(从
0 开始)。
forloop.revcounter 反向循环计数器(以最后一次循环为
1 ,反向计数)。
forloop.revcounter0 反向循环计数器(以最后一次循环为
0 ,反向计数)。
forloop.first 当前循环为首个循环时,该变量为True
forloop.last 当前循环为最后一个循环时,该变量为True
forloop.parentloop 在嵌套循环中,指向当前循环的上级循环

- Django模板 标签URL

返回与给定视图和可选参数相匹配的绝对路径引用(不含域名的 URL)

  • 1 {% url 'some-url-name' v1 v2 %} 2 第一个参数是 url 模式名称,后面跟着的是参数,以空格分隔 3 4 可以使用关键字: 5 {% url 'some-url-name' arg1=v1 arg2=v2 %} 6 7 如果您想检索命名空间的 URL ,请指定完全限定的名称: 8 {% url 'myapp:view-name' %}

- Django模板 标签with

{% with %} 和 {% endwith %} , 简单的名称缓存复杂变量,当访问多次耗时 的方法(例如操作数据库的方法):

1 {% with total=business.employees.count%} 2 {{ total }} employee 3 {% endwith %} 4 5 {% with a=1 b=2 %} 6 ... 7 {% endwith %}

备注

仍然支持以前比较啰嗦的格式:

{% with total=business.employees.count%}

{% with business.employees.count as total %}

- Django模板 标签csrf_token

csrf_token是解决CSRF跨站请求伪造的方式

CSRF 案例

注意

Django提供CSRF的中间件

代码

  • 1 # 无参数标签 csrf_token ,这个标签是用于 html 进行 form 表单提交时,包含一个 随机变化的字符串,在 html 页 面中,其实就是一个 input type='hidden'

  • 2 # 作用是用于防止跨域攻击 3 {% csrf_token %}

- Django模板 过滤器

过滤器: 过滤器转换变量和标签参数的值

通过 | 来使用

示例:

1 {{ value|add:"2" }}

value: 是模板中获取的对象 add: 是过滤器 “2”: 是过滤器add的参数,只支持一个参数

length:messages|length这里判断 messages 不为空,并且长度 大于等于100

  • 1 {% if messages|length >= 100 %} 2 You have lots of messages today!

  • 3 {% endif %}

divisibleby:能否整除,返回 True和False

  • 1 {{ value|divisibleby:"2" }}

capfirst:首字母大写,只对字符串的第一个单词的首字母大写

  • 1 {{ value|capfirst }} 2 如果 value 是 "django is good" ,输出将是 "Django is 。

  • good"

center:将值置于给定宽度的字段中

  • " "

  • 1 {{ value|center:"15" }} 2 如果 value 是 "Django" ,输出将是。 " Django " ,前面 5 个,后面 4 个空格

cut:删除给定字符

  • 1 {{ value|cut:" " }} 2 如果 value 是 "String with spaces" ,输出将 是: "Stringwithspaces"

title:通过使单词以大写字母开头,其余字符以小写字母开头,将 字符串转换为大写字母

  • 1 {{ value|title }} 2 如果 value 是 "my FIRST post" ,则输出将是 "My First Post"

date:日期字符串

1 格式字符 描述 示例 输出
2 b月,文字,3个字母,小写。’jan’
3 d每月的一天,2位数字前导零。’01’至’31’
4 D星期几,文字,3个字母。’Fri’
5 e时区名称。可能是任何格式,或者可能会返回一个空字
符串,具体取决于日期时间。
‘’,’GMT’,’-500’,’US/Eastern’,等。
6 E月,通常用于长日期表示的区域设置特定备选表示。
‘listopada’(对于波兰语区而言’Listopad’)
7 f时间在12小时和分钟之内,如果它们为零,则分钟时间
不再。专有扩展。’1’,’1:30’
8 F月,文字,长。’January’
9 g小时,12小时制,无前导零。’1’至’12’
10 G小时,24小时制,无前导零。’0’至’23’
11 h小时,12小时制。’01’至’12’
12 H小时,24小时制。’00’至’23’
13 i分钟。’00’至’59’
14 I夏令时,无论是否有效。’1’ or ‘0’
15 J没有前导零的月份的一天。’1’至’31’
16 n月没有前导零。’1’至’12’
17 N月份’Jan.’, ‘Feb.’, ‘March’, ‘Jan.’, ‘Feb.’, ‘March’,
‘May’
18 s秒00-59
19 t给定月份的天数。28至31
20 T这台机器的时区。’EST’,’MDT’
21 u微秒。000000至999999
22 U Unix时代以来的秒数(1970年1月1日00:00:00
UTC)。
23 w ^没有前导零的数字。’0’(星期日)至’6’(星期
六)

24 W ^ ISO-8601 周数,周数从周一开始。 1 , 53 25 y 年, 2 位数字。 '99' 26 Y 年, 4 位数字。 '1999' 27 z 一年中的一天。 0 至 365 28 Z 以秒为单位的时区偏移量。 UTC 以西时区的偏移总是负 值,而 UTC 以东的偏移总是正值。 -43200 至 43200 29 30 31 {{ value|date:"D d M Y" }} 32 {{ value|date:"Y-m-d H:i:s" }} 33 value : datetime.datetime.now()

- Django模板 静态文件

除了服务端生成的 HTML 以外,网络应用通常需要一些额外的文件 —— —— 比如图片,脚本和样式表 来帮助渲染网络页面。在 Django 中,我们把这些文件统称为“静态文件”

注意

静态文件一般会由专门的静态服务器提供

O 1 settings中配置

  • 1 # staticfiles 只在 DEBUG=True 的情况下有效, 生产环境中使用 服务器(如 nginx )的静态文件管理

  • 2 INSTALLED_APPS = [ 3 'django.contrib.staticfiles', 4 ] 5 STATIC_URL = '/static/' 6 # 指定静态文件保存的目录,默认是各个子应用下的 static 文件夹

  • 7 "C:/Users/user/mysite/extra_static_content "

  • 8 STATICFILES_DIRS = [ 9 "/home/special.polls.com/polls/static",

  • 10 "/home/polls.com/polls/static", 11 "/opt/webfiles/common", 12 ]

@ 2 在子应用下建立目录 static, 存放 静态文件 @ 3 模板文件中

1 {% load static %} # 写在模板中第一行 2 3 # 图片 " " 4 <img src= {% static "images/hi.jpg" %} alt="Hi!"> 5 6 # css " 7 <link rel="stylesheet" href= {% static " = 'css/mystyle.css' %} type "text/css" media="screen"> 8 9 # javascript ' 10 <script type='text/javascript' src= {% static 'js/myjs.js' %}'></script>

get_static_prefix 在模板中指定 settings 中配置的 STATIC_URL 1 {% load static %} 2 " 3 <img src= {% get_static_prefix %}images/hi.jpg" alt="Hi!"> 4 # 等同于 " " 5 <img src= {% static "images/hi.jpg" %} alt="Hi!">

Django模板-include标签

加载一个模板,并在当前上下文中进行渲染。这是一种在模板中 “包 含” 其他模板的方式

简单的理解:在当前模板中 引入 另外一个模板内容

使用方法

模板名称可以是变量,也可以是单引号或双引号的硬编码(带引 号)的字符串

1

  • {% include "foo/bar.html" %}

2

  • 3 {% include template_name %}

include传参数

view传参

context:

  • 1 render(request, 'temp.html',{'greeting': 'hello', 'person': 'John'})

temp.html模板:

  • 1 {{ greeting }}, {{ person }}!

模板传参

  • 原模板通过with传递参数

  • 1 {% include "name_snippet.html" with person="John" greeting="Hello" %}

注意

模板与view同时传参,模板参数值 优先 view参数

- Django模板 模板继承

模板继承允许构建一个基本“骨架”模板,其中包含您网站的所有常 见元素,并定义子模板可以覆盖的 block

定义父模板

如下,定义一个base.html, 如下:

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <link rel="stylesheet" href="style.css" />

  • 5 <title>{% block title %}My amazing site{% endblock %}</title>

  • 6 </head> 7

  • 8 <body> 9 <div id="sidebar">

  • 10 {% block sidebar %} 11 <ul> 12 <li><a href="/">Home</a></li> 13 <li><a href="/blog/">Blog</a> </li>

  • 14 </ul> 15 {% endblock %} 16 </div> 17 <div id="content"> 18 {% block content %}{% endblock %} 19 </div>

  • 20 </body> 21 </html>

上面这个模板中,定义了3个 block :

  • title

  • sidebar

  • content

block的基本使用方法:{% block title %} {% endblock %}

继承父模板

子页面detail.html继承上面这个base.html,内容如下:

  • 1 {% extends "base.html" %} 2 3 {% block title %}My amazing blog{% endblock %}

4 5 {% block content %} 6 {% for entry in blog_entries %} 7 <h2>{{ entry.title }}</h2> 8 <p>{{ entry.body }}</p> 9 {% endfor %} 10 {% endblock %} 11

使用{% extends “base.html” %} 继承 base.html,本页面有2个 block,对应base.html的2个block,会在base.html中,使用本 detail.html的对应内容进行替换,而block sidebar 并没有对应的 block,因此继续使用base.html的 sidebar 的内容

继承的技巧

  • 如果在模板中使用,{% extends %}必须是该模板中的第一个模板标签。否则模板继承将不起作 用。

  • 基本模板中的越多{% block %}标签越好。子模板不必定义所有父块,因此可以在多个块中填写合 理的默认值

  • 如果发现自己在多个模板中复制了内容,则可能意味着您应该将该内容移至父模板的 {% block %}

  • 如果需要从父模板中获取块的内容,则使用 {{ block.super }}

  • 1 {% block sidebar %}

  • 2 {{ block.super }} 3 新的内容 4 {% endblock %}

    • 在使用模板标签语法之外创建的变量不能在块 oe, {% block% } 内使用。例如,该模板不会呈现任何内 容
  • 1 {% trans "Title" as title %} 2 {% block content %}{{ title }}{% endblock %}

为了增加可读性,您可以选择为您的结束标签 命名。例如: {% endblock content %}

  • 1 {% block content %}

  • 2

  • 3 {% endblock content %}

Django后台管理-admin介绍

Django 最强大的部分之一是自动管理界面。它从你的模型中读取元 数据,提供一个快速的、以模型为中心的界面,受信任的用户可以 管理你网站上的内容

提示

后台管理系统是管理人员使用,不是给客户使用 此应用默认是开启的

后台管理设置

settings.py

1 INSTALLED_APPS = ['django.contrib.admin']

URL路由

1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 ]

后台管理初识

若想使用后台管理需要同步数据表,并建立用户

同步数据表

  • 1 python manager.py makegirations

  • 2 python manager.py migrate

建立用户

  • 1 python manager.py createsuperuser

输入用户名

  • 1 Username: admin

输入邮箱

  • 1 Email address: admin@example.com

输入密码

  • 1 Password: **********

  • 2 Password (again): *********

  • 3 Superuser created successfully.

- Django后台管理 基本使用

默认管理后台,是不会加载应用的APP模型,需要手动配置,步骤 如下:

建立模型

增加模型到管理后台

测试使用

浏览器查看效果

建立模型

在model.py中:

  • 1 class Student(models.Model):

  • 2 name = models.CharField(max_length=20)

  • 3 age = models.IntegerField()

  • 4

  • 5 class Meta:

  • 6 db_table='t_student'

添加模型管理

在admin.py中:

  • 1 from django.contrib import admin

  • 2 from .models import Student

  • 3

  • 4 admin.site.register(Student)

在浏览器中访问

访问path为 /admin, 譬如:http://127.0.0.1:8000/admin

- Django后台管理 名称显示管理

设置字段名

在字段上设置verbose_name属性标明即可

  • 1 class Student(models.Model): 2 # 增加 verbose_name 3 name = models.CharField(max_length=20, ' '

  • =

  • verbose_name 姓名 )

  • 4 # 增加 help_text '

  • 5 age = models.IntegerField(help_text= 大于 ' '

  • 18', verbose_name= 年龄 )

设置对象名

在模型Meta内部类中设置verbose_name属性即可

1 class Student(models.Model): 2 # 增加 verbose_name 3 name = models.CharField(max_length=20, ' ' = verbose_name 姓名 ) 4 # 增加 help_text ' 5 age = models.IntegerField(help_text= 大于 ' ' 18', verbose_name= 年龄 ) 6 # 增加 Meta 类 7 class Meta: 8 # verbose_name_plural : 复数形式 9 verbose_name_plural = verbose_name = ' 学生 '

设置对象显示方式

重新模型类的 str 方法即可

1 class Student(models.Model): 2 # 增加 verbose_name 3 name = models.CharField(max_length=20, ' ' = verbose_name 姓名 ) 4 # 增加 help_text ' 5 age = models.IntegerField(help_text= 大于 ' ' 18', verbose_name= 年龄 ) 6 # 模型类的 字符串化 7 def __str__(self): 8 return f'{self.name}({self.pk})'

设置应用名

在子应用下的 apps.py中设置verbose_name属性即可

  • 1 class TestAppConfig(AppConfig): ' '

  • 2 verbose_name = 子应用名

额外提示

模型设置的内容,不会不同的形式显示在管理后台

  • 1 class Student(models.Model):

  • 2 ' ' ' '

  • 3 SEX_CHOICES = ((1, 男 )), (2, 女 ) 4 # 增加 verbose_name 5 name = models.CharField(max_length=20, ' '

  • =

  • verbose_name 姓名 )

  • 6 # 增加 help_text '

  • 7 age = models.IntegerField(help_text= 大于 ' '

  • 18', verbose_name= 年龄 )

  • 8 # 修改已有模型,增加新字段的话,都需要设置默认值 或者设置 null=True

  • 9 sex = models.IntegerField(choices=SEX_CHOICES, ' '

  • default=1 , verbose_name= 性别 )

  • 10 11 # 增加 Meta 类 12 class Meta: 13 # verbose_name_plural : 复数形式 14 verbose_name_plural = verbose_name = ' 学生 '

  • 15 16 # 模型类的 字符串化

17

18 return f'{self.name}({self.pk})'

def __str__(self):

- Django后台管理 关联关系的演示

==> picture [19 x 10] intentionally omitted <==

—– Start of picture text —–

170
—– End of picture text —–

后台管理系统对于有关联关系的模型,也有着友好的支持,下面代 码中,分别定义了不同关联关系:

Place —— Restaurant 1对1

  • Restaurant —— Waiter 1对多 Restaurant —— Food 多对多

模型的建立

  • 1 from django.db import models

  • 2

  • 3 # Create your models here.

  • 4 class Place(models.Model): """

  • 5

  • 6 位置信息

  • 7 """

  • 8 name =

    • models.CharField(max_length=32,verbose_name= ' 地名 ')
  • 9 address = models.CharField(max_length=64,null=True,ver ' '

  • bose_name= 地址 )

  • 10 11 class Meta:

  • 12 db_table='t_place'

13

14 class Restaurant(models.Model):

""" 15 16 餐厅 17 """ 18 name = models.CharField(max_length=32,verbose_name= ' 餐厅名 ')

19 place =

models.OneToOneField(Place,on_delete=models. ' ' CASCADE,verbose_name= 所在位置 ,null=True)

20 21 class Meta: 22 db_table='t_restaurant'

23 24 class Waiter(models.Model): """ 25 26 服务员 27 """ 28 name = models.CharField(max_length=32,verbose_name= ' 人名 ') 29 induction = ' models.DateTimeField(verbose_name= 入职时 ' 间 ,null=True) 30 restaurant = models.ForeignKey(Restaurant,on_delete=mode ' ' ls.CASCADE,verbose_name= 所在餐厅 ,null=True) 31 def __str__(self): 32 return f'{self.name} == ' {self.induction} 33 class Meta: 34 db_table='t_waiter'

35

36 class Food(models.Model): """ 37 38 食物 39 """ 40 name =

models.CharField(max_length=32,verbose_name= ' 菜名 ') 41 is_main =

models.BooleanField(default=True,verbose_nam ' ' e= 是否是主食 ,null=True) 42 restaurant = models.ManyToManyField(Restaurant,verbose_na ' ' me= 哪个餐厅有 ,null=True) 43 class Meta: 44 db_table='t_food'

- Django后台管理 自定义注册管理类介绍

注册模型除了使用 Django 默认的管理类admin,也可以自定义, 比如:

  • 1 class StudentAdmin(admin.ModelAdmin): 2 pass 3 admin.site.register(Student, StudentAdmin)

ModelAdmin 类是管理界面中模型的表示。通常,这些都存储在你的应 用程序中一个名为 admin.py 的文件中

提示

如果你对默认的管理界面满意,你根本不需要定义一个

ModelAdmin 对象

自定义管理类的属性:

  • 1 class StudentAdmin(admin.ModelAdmin):

  • 2 # 显示的属性列表, 值是 属性名 3 list_display = ['name', 'age'] 4 # 排序的 属性 列表 , 默认是升序,如果需要降序: ['-age']

  • 5 ordering = ['age'] 6 admin.site.register(Student, StudentAdmin)

装饰器注册类

该装饰器使用的是 admin.register , 不是 admin.site.register

  • 1 @admin.register(Student)

  • 2 class StudentAdmin(admin.ModelAdmin): 3

  • 4 list_display = ['name', 'age'] 5 ordering = ['age']

- Django后台管理 自定义注册管理类属性

empty_value_display

属性为空时,在网页上显示的内容,默认是: -

fields

管理的字段

exclude

不管理的字段

filter_horizontal

多对多关系,默认是 select多选框,一般使用 filter_horizontal 或者 filter_vertical

  • 1 from django.db import models

  • 2

  • 3 # Create your models here. 4 class Student(models.Model):

  • 5 name = models.CharField(max_length=20, ' '

  • verbose_name= 姓名 ,null=True,blank=True)

  • '

  • 6 age = models.IntegerField(help_text= 大于 ' '

  • 18', verbose_name= 年龄 )

  • 7

  • 8 # 增加 Meta 类 9 class Meta:

  • 10 verbose_name_plural = verbose_name = ' 学生 '

11 db_table = 't_student' 12 13 class Teacher(models.Model): 14 name = models.CharField(max_length=20, ' ' = verbose_name 姓名 ) 15 student = models.ManyToManyField(Student,verbose_name= ' ' 学生 ,null=True)

- Django后台管理 增加批量操作

后台管理系统默认提供的批量处理并不全,这时可以自己在 admin.py中定义。 使用actions属性即可 ,具体 下:

动作函数是 单独的模块函数

  • 1 # 定义动作函数 2 def age_add_one(modeladmin, request, queryset):

  • 3 queryset.update(age=F('age')+1) 4 # 给动作函数添加描述 " "

  • 5 age_add_one.short_description = 年龄增加一岁 6

  • 7 class StudentAdmin(admin.ModelAdmin): 8 # 在当前自定义管理类中,添加新的动作: age_add_one

  • 9 actions = [age_add_one]

  • 10 11 admin.site.register(Student, StudentAdmin)

动作函数写在 自定义管理类 中:

  • 1 class StudentAdmin(admin.ModelAdmin): 2 # 这里必须是函数名的字符串 3 actions = ['age_add_one'] 4 5 # 类方法也同样是 3 个参数! 6 def age_add_one(modeladmin, request, queryset):

  • 7 queryset.update(age=F('age') + 1) 8 "

  • 9 age_add_one.short_description = 年龄增加 一岁 "

  • 10 11 admin.site.register(Student, StudentAdmin)

- Django后台管理 覆盖管理模板

如果我们要在admin管理页面中,增加自己的功能,那么我们需要 覆盖admin的默认模板

admin管理模板目录

django库下的 contrib/admin/templates/admin 目录,可以查看django自带的 所有模板

可以覆盖的模板

contrib/admin/templates/admin 中的模板并非每个应用程序或每个模型都可

以被覆盖。以下情况可以:

  • actions.html

  • app_index.html

  • change_form.html

  • change_form_object_tools.html

  • change_list.html

  • change_list_object_tools.html

  • change_list_results.html

  • date_hierarchy.html

  • delete_confirmation.html

  • object_history.html

  • pagination.html

  • popup_response.html

  • prepopulated_fields_js.html

  • search_form.html

  • submit_line.html

自定义模板

需要修改admin的哪个内置模板,则继承哪个模板,并且在其基础 上进行修改,我们以app_index.html为例:

原始模板

  • 1 {% extends "admin/index.html" %}

  • 2 {% load i18n %} 3

  • 4 {% block bodyclass %}{{ block.super }} app{{ app_label }}{% endblock %}

  • 5 6 {% if not is_popup %} 7 {% block breadcrumbs %} 8 <div class="breadcrumbs">

  • 9 <a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>

  • 10 &rsaquo; 11 {% for app in app_list %} 12 {{ app.name }} 13 {% endfor %} 14 </div> 15 {% endblock %} 16 {% endif %}

17

{% block sidebar %}{% endblock %}

18

自定义编写模板

  • 1 {% extends "admin/app_index.html" %} 2

  • 3 {% block sidebar %} 4 <a href="{% url 'children:customize' %}"> 自定义功能页面 </a>

  • 5 {% endblock %}

  • 将改的模板放到当前子应用的文件templates\admin\子应用名的目 录下即可

Django会话-Cookie介绍

背景介绍

HTTP协议有一个特性就是无状态的,是指协议对于交互性场景没有 记忆能力

随着动态交互的web应用的出现,HTTP的无状态特性严重阻碍了动 态交互应用程序的发展,例如一些购物网站在进行购物时候都会进 行了页面跳转/刷新,按照HTTP的无状态协议岂不是登录一次又一 次。于是,两种用于保持http连接状态的技术就应运而生了,这个 就是Session和Cookie

Cookie简介

Cookie,有时也用Cookies,是指web程序为了辨别用户身份、进 行 session 跟踪而储存在用户本地终端上的数据(通常经过加 密),一般是以键值对的形式存在,Cookie具有不可跨域名性 Cookie是http协议中定义在 header 中的字段

Cookie解决无状态问题原理

Cookie 技术通过在请求和响应报文中写入Cookie 信息来控制客户 端的状态。

Cookie 会根据从服务器端发送的响应报文内的一个叫做Set-Cookie 的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服 务器发送请求时,客户端会自动在请求报文中加入Cookie 值后发送

出去。

服务器端发现客户端发送过来的Cookie 后,会去检查究竟是从哪一 个客户端发来的连接请求,然后对比服务器上的记录,最后得到之 前的状态信息。

没有Cookie信息状态下的请求

  • 第2次以后(存有Cookie信息状态)的请求

11 <form action="/do_login/" method="post"> 12 {% csrf_token %} 13 用户名 :<input type="text" "" name="uname" id= ><br> 14 密码 :<input type="password" "" name="pwd" id= ><br> 15 记住我 <input type="checkbox" name="rember" value="rember"><br> " " 16 <input type="submit" value= 登录 > <br> 17 </form> 18 </body> 19 </html>

@ 3 处理视图函数 1 from django.shortcuts import render,redirect 2 from django.http import HttpResponse 3 4 # Create your views here. 5 def login(request): 6 return render(request,'login.html') 7 8 def do_login(request): ''' 9 10 登录操作 11 ''' 12 # 建立一个响应结果对象 13 resp = HttpResponse() 14 # 获取用户传递来的数据

15 data = request.POST 16 # 获取用户名 17 uname = data.get('uname') 18 # 获取密码 19 pwd = data.get('pwd') 20 # 获取是否勾选记住我 21 rember = data.get('rember') 22 23 # 判断是否登录成功 24 if uname == 'baizhan' and pwd=='123': ' ' 25 resp.content = 登录成功 26 if rember == 'rember': 27 print('='*30) 28 # 创建 cookie 29 resp.set_cookie('uname',uname,max_age=60* 60*24*3) 30 # 设置密码 31 resp.set_signed_cookie('pwd',pwd,max_age= 60*60*24*3) 32 else: 33 # 删除 cookie 34 resp.delete_cookie('uname') 35 resp.delete_cookie('pwd') 36 return resp 37 else: 38 return redirect('/login/')

Django会话-Session的介绍

Session,在计算机中,尤其是在网络应用中,称为“会话控制”。

Session 对象存储 特定用户会话所需的属性及配置信息 。当用户请 求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服 务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务 器将终止该会话

当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中 的变量将不会丢失,而且在整个用户会话中一直存在下去。

会话状态仅在支持 cookie 的浏览器中保留 (session是依赖于 cookie的)

Django框架中的session管理 允许存储和检索 任意数据,它在服务 器端存储数据并抽象cookie的发送和接收。Cookie包含session的 ID,而不是数据本身(除非使用基于cookie的session管理类型)

通过Cookie来管理Session

Django会话-Session的配置

启用session

要应用session,必须开启session中间层,在settings.py中:

1 MIDDLEWARE = [ 2 # 启用 Session 中间层 3 'django.contrib.sessions.middleware.SessionM iddleware', 4 ]

五种session的引擎

Django中默认支持Session,其内部提供了5种类型供开发者使用:

数据库 缓存 缓存+数据库 文件 Cookie

五种方式的启动配置各异,但是启动完成后,在程序中的使用方式 都相同:

数据库方式

  • 1 SESSION_ENGINE =

    • 'django.contrib.sessions.backends.db'
  • 2 # 数据库类型的 session 引擎需要开启此应用,启用 sessions 应用

3 INSTALLED_APPS = [ 4 'django.contrib.sessions', 5 ]

缓存

速度最快,但是由于数据是保存在内存中,所以不是持久性的, 服务器重启或者内存满了就会丢失数据

  • 1 SESSION_ENGINE =

'django.contrib.sessions.backends.cache'

+ 缓存 数据库

速度次于单纯缓存方式,但是实现了持久性,每次写入高速缓存 也将写入数据库,并且如果数据尚未存在于缓存中,则使用数据 库

  • 1 SESSION_ENGINE =

'django.contrib.sessions.backends.cached_d b'

文件

1 SESSION_ENGINE = 'django.contrib.sessions.backends.file'

2 # 设置文件位置, 默认是 tempfile.gettempdir() , 3 # linux 下是: /tmp 4 # windows 下是: C:\Users\51508\AppData\Local\Temp 5 SESSION_FILE_PATH = 'd:\session_dir'

加密cookie

  • 基于cookie的session,所有数据都保存在cookie中,一般情况 下不建议使用这种方式

  • ] 1 cookie有长度限制,4096个字节

  • @ 2 cookie不会因为服务端的注销而无效,那么可能造成攻击者使用已经登出的cookie模仿用户 继续访问网站

  • @ 3 SECRET_KEY这个配置项绝对不能泄露,否则会让攻击者可以远程执行任意代码

  • e 4 cookie过大,会影响用户访问速度

  • 1 SESSION_ENGINE =

'django.contrib.sessions.backends.signed_c ookies'

Django会话-Session的使用

创建与获取session

在django程序中通过 request.session 来获取session对象,并且这 个session就是一个字典对象,并且 key 只能是 字符串

  • 1 request.session['has_commented'] = True

  • 2 # 获取某个 session 变量

  • 3 has_commented =

request.session.get('has_commented')

删除session

1 # 删除某个 key

  • 2 del request.session['has_commented']

  • 3 # 从会话中删除当前会话数据并删除会话 cookie

  • 4 flush()

  • 5 # 设置会话的到期时间

  • 6 # 如果 value 是整数,则 session 将在多少秒不活动后到期

  • 7 # 如果 value 是一个 datetime 或 timedelta ,该 session 将在相应的日期 / 时间到期

  • 8 # 如果 value 是 0 ,用户的会话 cookie 将在用户的 Web 浏览 器关闭时到期

  • 9 # 如果 value 是 None ,则会话将恢复为使用全局会话到期策 略

  • 10 set_expiry(value)

其他session方法

  • 1 # 设置测试 cookie 以确定用户的浏览器是否支持 cookie 2 set_test_cookie()

  • 3 # 返回 True 或者 False ,取决于用户的浏览器是否接受测试 cookie

  • 4 test_cookie_worked()

  • 5 # 删除测试 cookie

  • 6 delete_test_cookie()

  • 7 # 返回此会话到期之前的秒数

  • 8 # kwargs 为 modificationexpiry ,一般不 指定

  • 9 # modification :最后一次访问日期,默认当前时间, now

  • 10 # expiry : 到期剩余秒数,默认全局配置时间

  • 11 get_expiry_age(**kwargs)

  • 12 # 返回此会话将过期的日期

  • 13 # 参数同 get_expiry_age 14 get_expiry_date(**kwargs)

  • 15 # 返回 True 或者 False ,取决于用户的 Web 浏览器关闭时用 户的会话 cookie 是否会过期

  • 16 get_expire_at_browser_close()

  • 17 # 从会话存储中删除过期的会话,这是个类方法。

  • 18 clear_expired()

  • 19 # 在保留当前会话数据的同时创建新的会话密钥

  • 20 cycle_key()

session的settings.py使用

  • 1 # Session 的 cookie 保存在浏览器上时的 key ,即: sessionid =随机字符串(默认)

  • 2 SESSION_COOKIE_NAME = "sessionid"

  • 3 # Session 的 cookie 保存的路径(默认)

  • 4 SESSION_COOKIE_PATH = "/"

  • 5 # Session 的 cookie 保存的域名(默认)

  • 6 SESSION_COOKIE_DOMAIN = None

  • 7 # 是否 Https 传输 cookie (默认)

  • 8 SESSION_COOKIE_SECURE = False

  • 9 # 是否 Session 的 cookie 只支持 http 传输(默认)

  • 10 SESSION_COOKIE_HTTPONLY = True 11 # Session 的 cookie 失效日期( 2 周)(默认) 12 SESSION_COOKIE_AGE = 1209600 13 # 是否关闭浏览器使得 Session 过期(默认) 14 SESSION_EXPIRE_AT_BROWSER_CLOSE = False 15 # 是否每次请求都保存 Session ,默认修改之后才保存(默 认)

  • 16 SESSION_SAVE_EVERY_REQUEST = False

Django会话-Session实现登录

要求:

用django后台管理的用户登录验证

实现登录功能

django.contrib.auth

-

实现退出用户功能

没登录自动跳登录页面

django.contrib.auth.decorators.login_required 实现

urls:

  • 1 urlpatterns = [ ''

  • 2 path( , views.index, name='index'), 3 path('login/', views.login, name='login'),

  • 4 path('logout/', views.logout,

    • name='logout'),
  • 5 ]

views:

  • 1 @login_required(login_url='test_app:login') 2 def index(request): 3 return render(request, 'index.html') 4

  • 5 def logout(request): 6 auth.logout(request)

  • 7 return redirect('test_app:login')

  • 8

  • 9 def login(request):

  • 10 if request.method == 'GET':

==> picture [442 x 766] intentionally omitted <==

—– Start of picture text —–

11 error_message =
request.session.get(‘error_message’)
12 request.session[‘error_message’] =
None
13 return render(request, ‘login.html’,
{‘error_message’: error_message})
14 else:
15 username = request.POST[‘username’]
16 password = request.POST[‘password’]
17
18 # django authenticate 中获取对应的用户
名和密码的 ORM 对象
19 user =
auth.authenticate(username=username,
=
password password)
20
21 if user:
22 # 将登陆的用户写入到 session 中, 在其
它视图函数中用 request.user 获取用户对象
23 auth.login(request, user)
24 return
redirect(‘test_app:index’)
25 else:
26 request.session[‘error_message’]
= 用户名或密码错误 !’
27 return
redirect(‘test_app:login’)
index.html:
1
2 <html lang=”en”>
3

—– End of picture text —–

  • 4 <meta charset="UTF-8"> 5 <title> 首页 </title> 6 </head> 7 <body> 8 欢迎 {{ request.user.username }} 光临 9 <br> " "

  • 10 <a href= {% url 'test_app:logout' %} > 退 出登录 </a>

  • 11 </body> 12 </html> 13 14 15

: login.html

  • 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title> 登录页面 </title> 6 </head> 7 <body> "

  • 8 <form action= {% url 'test_app:login' "

  • %} method="POST">

  • 9 {% csrf_token %}

  • 10 用户名: <input type="text" name="username">

  • 11 <br> 12 密码: <input type="password" name="password">

  • 13 <br>

14 {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} 15 <br> " " 16 <input type="submit" value= 登录 > 17 </form> 18 </body> 19 </html>

- Django工具 分页器介绍

介绍

分页,就是当我们在页面中显示一些信息列表,内容过多,一个页 面显示不完,需要分成多个页面进行显示时,使用的技术就是分页 技术

==> picture [19 x 10] intentionally omitted <==

—– Start of picture text —–

203
—– End of picture text —–

在django项目中,一般是使用3种分页的技术:

  • 1 自定义分页功能,所有的分页功能都是自己实现

  • 2 django的插件 django-pagination 实现

  • 3 django自带的分页器 paginator

分页器相关对象

分页器的对象在 django/core/paginator.py 模块中,主要包括Paginator类

和Page类:

Paginator类

1 初始化方法__init__(self, object_list, per_page,

: orphans=0,allow_empty_first_page=True)

  • object_list:可以是QuerySet、带有count()或__len__()方法的列表、元组或其它可切片的对 象,如果是QuerySet,应该进行排序,使用order_by()子句或者有默认的ordering

  • per_page:每个页面上显示的项目数目,不包括orphans部分

  • orphans:默认为0,如果最后一页显示的数目小于等于该数值,那么则将最后一页的内容(假 设数为N)添加到倒数第二页中去,这样的话倒数第二页就成了最后一页,显示的数目为: per_page+N

  • allow_empty_first_page:默认为True,允许第一页显示空白内容,如果设置为False,那么 当object_list为空时,抛出EmptyPage错误

2 方法

  • 1

get_page(self, number)

numer:指定页码数,正确值应该是大于等于1的整数

返回指定number的Page对象,同时还处理超出范围和无效

页码,如果number不是数字,则返回第一页,如果number 为负数或大于最大页数,则返回最后一页。

  • ] 2 page(self, number)

    • numer:指定页码数,正确值应该是大于等于1的整数

返回指定number的Page对象,不处理异常,如果number 无效,则抛出 InvalidPage 错误

e 3 属性

  • e 1 count:项目总条数,调用该属性时,优先调用object_list的count()方法,没有count()方法才 尝试len(object_list)方法

  • e 2 num_pages:总页码数

  • ) 3 page_range:从1开始的页码迭代器,代码:range(1, self.num_pages + 1)

Page类

一般情况下,不会手动实例化该类,而是通过Paginator的page 或者get_page方法获取

  • e 1 初始化方法__init__(self, object_list, number, paginator):

    • object_list:当页显示的object_list对象,object_list可以是QuerySet、带有count()或 len()方法的列表、元组或其它可切片的对象

    • number:页码数

    • paginator:Paginator类的实例

  • e 2 方法

主要的方法都是用来做逻辑判断的,以此来决定页面中显示的诸

如:上一页、下一页,首页,末页等

  • e 1 has_next():如果有下一页则返回True

  • @ 2 has_previous():如果有上一页,则返回True

  • @ 3 has_other_pages():如果有上一页或者下一页,则返回True

  • @ 4 next_page_number():返回下一页编号,如果下一页不存在则引发 InvalidPage 错误

  • e 5 previous_page_number():返回上一页编号,如果上一页不存在则引发 InvalidPage 错误

  • e 6 start_index() :返回页面上第一个对象的从1开始的索引,相对于分页器列表中的所有对象。 例如,当为每页包含2个对象的5个对象的列表进行分页时,第二个页面Page对象的 start_index返回3

  • @ 7 end_index() :返回页面上最后一个对象的从1开始的索引,相对于分页器列表中的所有对 象。例如,当为每页包含2个对象的5个对象的列表进行分页时,第二个页面Page对象的 end_index返回4

@ 3 属性

其实就是初始化方法中的3个参数

@ 1 object_list:对应的object_list

  • e 2 number:该对象的所处的页码数,从1开始

@ 3 paginator:关联的Paginator实例

- Django工具 分页器的实战

初始化数据

  • e 1 新建django项目:paginator_study,子应用:paginator_app e 2 在mysql数据库新建 paginator_study 库

  • @ 3 settings中配置数据库:

1 DATABASES = { 2 'default': { 3 'ENGINE': 'django.db.backends.mysql', 4 'NAME': 'paginator_study ', 5 'USER': 'root', 6 'PASSWORD': '123', 7 'HOST': '127.0.0.1', 8 'PORT': 3306, 9 } 10 }

==> picture [95 x 16] intentionally omitted <==

—– Start of picture text —–

e 4 建立模型:
—– End of picture text —–

1 class Student(models.Model):

  • 2 name = models.CharField(max_length=20)

  • 3 age = models.IntegerField() 4 sex = models.IntegerField(choices=((1, ' ' ' ' 男 ), (2, 女 )), default=1)

  • 5 card_no = models.CharField(max_length=18)

  • e 5 迁移数据库

    • 1 python manage.py makemigrations

    • 2 python manage.py migrate paginator_app

e 6 生成测试数据 model中增加 批量插入测试数据的方法:

  • 1 @classmethod

  • 2 def insert_test_data(cls, num=100):

  • 3 def random_str(raw_ite, length): 4 return '' .join(random.choices(raw_ite, k=length))

  • 5 6 obj_list = [] 7 for _ in range(num):

8 obj_list.append(Student( 9 name=random_str(string.ascii_lowercase, 8), 10 age=random.randint(18, 50), 11 sex=random.choice([1, 2]), 12 card_no=random_str(string.digits, 18) 13 )) 14

15 Student.objects.bulk_create(obj_list)

然后在 python manage.py shell 中调用该方法

  • 1 $ python manage.py shell 2 $ from paginator_app.models import * 3 $ Student.insert_test_data()

数据的基本显示

  • ) 1 urls增加路由配置

1 from django.urls import path 2 3 from .views import index 4 5 urlpatterns =[ 6 path('students/',index,name= 'stu') 7 ]

e 2 views中实现函数

1 from django.shortcuts import render 2 3 from .models import Student 4 # Create your views here. 5 def index(request): 6 # 获取数据 7 student_list = Student.objects.all() 8 # 将数据和模板一起返回 9 return render(request,'student.html', {'student_list':student_list})

@ 3 页面显示

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head>

4
5 <meta http-equiv=”X-UA-Compatible”
content=”IE=edge”>
6 <meta name=”viewport”
content=”width=device-width, initial-
scale=1.0”>
7 Document
8
9
10

学生列表

11
12
13 姓名
14 性别
15 年龄
16 身份证号
17
18 {% for stu in student_list %} {% for stu in student_list %}
19
20 {{ forloop.counter }}
21 {{ stu.name }}
22 {{ stu.sex }}
23 {{ stu.age }}
24 {{ stu.card_no }}
25
26 {% endfor %} {% endfor %}
27
28
29
30

e 4 编写样式 static>>css>>paginator.css

1 table

2 { 3 border-collapse: collapse; 4 text-align: center; 5 } 6 7 table td, table th 8 { 9 border: 1px solid #cad9ea; 10 color: #666; 11 height: 35px; 12 } 13 14 table thead th 15 { 16 background-color: #CCE8EB; 17 width: 100px; 18 } 19 20 table tr:nth-child(odd) 21 { 22 background: #fff; 23 } 24 25 table tr:nth-child(even) 26 { 27 background: #F5FAFA; 28 }

e 5 加载静态文件

  • 1 {% load static %} 2 <link rel="stylesheet" href="{% static >

  • 'css/paginator.css' %}"

使用分页器

==> picture [434 x 503] intentionally omitted <==

—– Start of picture text —–

@ 1 修改返回数据
1 from django.core.paginator import
Paginator
2 from django.conf import settings
3
4 def index_page(request):
5 # 获取要页面码
6 page = request.GET.get(‘page’)
7 # 获取数据
8 student_list =
Student.objects.all().order_by(‘age’)
9 # 初始化分页器
10 pageinator =
Paginator(student_list,settings.PAGE_SIZE)
11 # 获取指定页码的数据
12 =
students_page
pageinator.get_page(page)
13 # 返回数据
14 return
render(request,’student_page.html’,
{‘student_list’:students_page})

—– End of picture text —–

e 2 增加分页栏

1 <nav>

2 <ul> 3 <li><a href="?page=1"> 首页 </a> </li> 4 {% if student_list.has_previous %} 5 <li><a href="?page= {{student_list.previous_page_number}}"> 上 一页 </li>

6 {% endif %}

7 {% if student_list.has_next %} 8 <li><a href="?page= {{student_list.next_page_number}}"> 下一页 </li>

9 {% endif %} 10 <li><a href="?page= {{student_list.paginator.num_pages}}"> 末页 </a></li>

11 </ul> 12 </nav>

  • @ 3 设置样式 1 ul,li{ padding:0; margin:0;liststyle:none}

  • 2 .nav{border:1px solid #000; width:510px; overflow:hidden}

  • 3 .nav li{ line-height:22px; float:left; padding:0 5px;}

  • 4 .nav li a:hover{ color:#F00} 5 nav li{line-height:22px; float:left; padding:0 6px;}

  • 6 nav li a{ color:#009900}

@ 4 优化页码

不显示全部页码,自定义处理函数

  • 1 def get_page_range(page,max_page,num=4): '''

  • 2 3 page: 当前页码码 4 max_page: 总页数多少 5 num: 设置当前页码前后各多少个数字 6 ''' 7 # 根据当前页生成前面数字 8 min = int(page)-num 9 # 设置最小的页码码,如果这个页码码,小于 1 ,则 设置为 1

  • 10 min= min if min > 1 else 1 11 12 # 根据当前页生成后面数字 13 max = int(page) + num -1 14 # 设置最大的页码号,如果这个号操作总页数,则 设置最大号码

  • 15 max = max if max < max_page else max_page

  • 16 17 # 返回数字序列 18 return range(min,max+1)

@ 5 提取共同页面 paginator_common.html

  • 1 <nav> 2 <ul> 3 <li><a href="?page=1"> 首页 </a> </li>

  • 4 {% if data_list.has_previous %}

5

<li><a href="?page=

{{data_list.previous_page_number}}"> 上一页 </li>

6 {% endif %} 7 8 {% for num in page_range %} 9 {% if num == data_list.number %}

10 <li><strong>{{num}} </strong></li>

11 {% else %} 12 <li><a href="?page= {{num}}">{{num}}</li> 13 {% endif %} 14 {% endfor %}

15 {% if data_list.has_next %} 16 <li><a href="?page= {{data_list.next_page_number}}"> 下一页 </li> 17 {% endif %} 18 <li><a href="?page= {{data_list.paginator.num_pages}}"> 末页 </a></li> 19 </ul> 20 </nav>

@ 6 引入共同页面 1 {% if data_list.object_list %} 2 {% include 'page_comment.html' %} 3 {% endif %}

注意

在 page_comment.html 中使用的 data_list和page_range需要 统一命名,否则会报错