准备工作
将不同day下的代码分目录管理,方便后续复习查阅
(testenv) [root@localhost projects]# ls
day01 day02
(testenv) [root@localhost projects]# mkdir day03
(testenv) [root@localhost projects]# cd day03
(testenv) [root@localhost day03]# django-admin startproject mysite3
(testenv) [root@localhost day03]# ls
mysite3 # 今日在mysite3项目进行操作
使用 Pycharm 打开新项目 mysite3,并设置解释器为 testenv 虚拟环境
修改基础配置 settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware', # 注释掉 csrf
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# ......
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS':[os.path.join(BASE_DIR,"templates")], #配置模板目录,项目根目录创建templates
# ......
LANGUAGE_CODE = 'zh-Hans' # 配置语言支持
TIME_ZONE = 'Asia/Shanghai' # 配置时区
静态文件处理
什么是静态文件
如:图片、音频、视频、css、js等
静态文件配置
静态文件的相关配置也在 settings.py 文件中进行配置
-
配置静态文件的 访问路径【该配置默认存在】
- 功能:通过哪个 url 地址找静态文件
- STATIC_URL = '/static/'
- 说明:指定访问静态文件时是需要通过 /static/xxx 或 http://127.0.0.18000/static/xxx 获取的,xxx表示具体的静态资源位置
-
配置静态文件的存储路径 STATICFILES_DIRS
-
STATICFILES_DIRS:保存的是静态文件在服务器端的存储位置,例如:
-
实验:使用Django显示静态图片资源
-
修改配置文件—settings.py 文件,添加指定参数配置
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),) # 注意元组中的逗号
在项目根目录创建 static文件夹
复制一张图放入 image 文件夹,图片可自行寻找(本地或网络均可)
在 mysite3项目/mysite3 创建 views.py 文件,在该文件中编写指定视图函数
from django.shortcuts import render
def test_static(request):
return render(request, "test_static.html")
在 mysite3/templates 中创建 test_static.html 模板文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>p
<img src="http://127.0.0.1:8000/static/image/Django.png" width="200px" height="200px">
<img src="/static/image/Django.png" width="200px" height="200px">
</body>
</html>
修改 mysite3/mysite3/urls.py 文件,添加路由配置
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
###day03###
path("test_static", views.test_static),
]
-
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_static,查看模板加载是否成功
修改 mysite3/templates 中的 test_static.html 模板文件,添加 django 加载静态文件的方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="http://127.0.0.1:8000/static/image/Django.png" width="200px" height="200px">
<img src="/static/image/Django.png" width="200px" height="200px">
{% load static %}
<img src="{% static 'image/Django.png' %}" width="200px" height="200px">
</body>
</html>
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_static,查看模板加载是否成功
查看网页源代码,django方式加载的图片url路径默认是相对显示的方式
修改 settings.py 文件中的 STATIC_URL 参数
STATIC_URL = '/statics/' # 多了个s
重启服务后再次刷新页面,只有 {% static 'xxx' %} 的方式可以显示
-
通过查看网页源代码,观察图片地址,发现带有标签的img标签图片地址会更动态
应用
理解与概念
应用在Django项目中是一个独立的业务模块,可以包含自己的路由,视图,模板,模型
实验:创建应用
-
用 manage.py 中的子命令 startapp 创建应用文件夹
(testenv) [root@localhost mysite3]# python3 manage.py startapp music
(testenv) [root@localhost mysite3]# ls
db.sqlite3 manage.py music mysite3 static templates
在 settings.py 的 INSTALLED_APPS 列表中配置安装此应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'music', # 安装应用
]
应用内部结构
-
migrations文件夹
- 保存数据迁移的中间文件
-
__init__.py
- 应用子包的初始化文件
-
admin.py
- 应用的后台管理配置文件
-
apps.py
- 应用的属性配置文件
-
models.py
- 与数据库相关的模型映射文件
-
tests.py
- 应用的单元测试文件
-
views.py
- 定义视图处理函数的文件
分布式路由
概念与理解
Django中,主路由配置文件(urls.py)可以不处理用户具体路由,主路由配置文件可以做请求的分发(分布式请求处理)。具体的请求可以由各自的应用来进行处理。
配置分布式路由
步骤1:主路由中调用include函数
语法: include(‘app名字.url模块名’) 作用: 用于将当前路由转到各个应用的路由配置文件的urlpatterns进行分布式处理
步骤2:应用下配置urls.py
应用下手动创建urls.py文件,内容结构同主路由完全一致
实验:配置分布式路由
-
修改 mysite3/mysite3/urls.py 主路由文件,修改路由配置
-
from django.urls import path, include from . import views urlpatterns = [ path('admin/', admin.site.urls), ###day03### path("test_static", views.test_static), path("music/", include("music.urls")), ]
在 mysite3/music 创建子路由 urls.py 文件,修改路由配置
-
from django.urls import path from . import views urlpatterns = [ # http://127.0.0.1:8000/music/index path("index", views.index_view), ]
修改 mysite3/music/views.py 视图文件,添加指定视图函数
-
from django.shortcuts import render from django.http import HttpResponse def index_view(request): return HttpResponse("这是音乐首页")
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/music/index,查看是否响应成功
练习:配置分布式路由
需求:创建两个应用
-
创建sport应用并注册
-
创建news应用并注册
-
创建分布式路由系统
- http://127.0.0.1:8000/sport/index,交给sport应用中的index_view()函数处理
- http://127.0.0.1:8000/news/index,交给news应用中的index_view()函数处理
解题过程
-
用 manage.py 中的子命令 startapp 创建应用文件夹
-
(testenv) [root@localhost mysite3]# python3 manage.py startapp sport (testenv) [root@localhost mysite3]# python3 manage.py startapp news (testenv) [root@localhost mysite3]# ls db.sqlite3 manage.py music mysite3 news sport static templates
在 settings.py 的 INSTALLED_APPS 列表中配置安装此应用
-
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'music', 'news', 'sport', ]
修改 mysite3/mysite3/urls.py 主路由文件,修改路由配置
-
from django.urls import path, include from . import views urlpatterns = [ path('admin/', admin.site.urls), ###day03### path("test_static", views.test_static), path("music/", include("music.urls")), path("sport/", include("sport.urls")), path("news/", include("news.urls")), ]
在 mysite3/sport 创建子路由 urls.py 文件,修改路由配置
-
from django.urls import path from . import views urlpatterns = [ # http://127.0.0.1:8000/sport/index path("index", views.index_view), ]
修改 mysite3/sport/views.py 视图文件,添加指定视图函数
-
from django.shortcuts import render from django.http import HttpResponse def index_view(request): return HttpResponse("这是体育首页")
在 mysite3/news 创建子路由 urls.py 文件,修改路由配置
-
from django.urls import path from . import views urlpatterns = [ # http://127.0.0.1:8000/news/index path("index", views.index_view), ]
修改 mysite3/news/views.py 视图文件,添加指定视图函数
-
from django.shortcuts import render from django.http import HttpResponse def index_view(request): return HttpResponse("这是新闻首页")
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/sport/index,查看是否响应成功
- 查看服务是否重启,浏览器访问:http://127.0.0.1:8000/news/index,查看是否响应成功
应用下的模板
概念与理解
-
应用内部可以配置模板目录
-
应用下手动创建templates文件夹
-
settings.py中开启应用模板功能
- TEMPLATES配置项中的 APP_DIRS 值为 True 即可
-
-
应用下templates和外层templates都存在时,Django得查找模板规则
- 优先查找外层templates目录下的模板
- 按 INSTALLED_APPS 配置下的应用顺序逐层查找
实验:在应用中配置模板文件
-
应用(news)下手动创建 templates 文件夹
在 settings.py 中开启应用模板功能
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "templates")],
'APP_DIRS': True, # 将改值改为True即可,默认为True
在 mysite3/news/templates 下创建 index.html 模板文件,编写模板内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新闻首页</title>
</head>
<body>
我是新闻频道首页
</body>
</html>
在 mysite3/news/views.py 中修改视图函数 index_view
from django.shortcuts import render
from django.http import HttpResponse
def index_view(request):
# return HttpResponse("这是新闻首页")
return render(request, "index.html")
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/news/index,查看模板加载是否成功
如果此时在外层的 templates 中也创建 index.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
我是首页
</body>
</html>
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/news/index,查看模板加载结果是否有冲突
ORM框架
定义
ORM(Object Relational Mapping)即对象关系映射,它是一种程序技术,它允许你使用类和对象对数据库进行操作,从而避免通过SQL语句操作数据库
作用
-
如果此时在外层的 templates 中也创建 index.html 文件,经测试后,会优先找外层文件
-
解决方式
-
将应用中存储模板的路径改为:应用下---templates---应用名---index.html
-
在 mysite3/news/views.py 中修改视图函数 index_view
-
def index_view(request): # return HttpResponse("这是新闻首页") return render(request, "news/index.html") # 修改渲染模板路径,改为APP内部模板路径
看服务是否重启,浏览器访问:http://127.0.0.1:8000/news/index,查看模板加载结果
-
模型层
概念与理解
回顾 Django MTV
-
模型层:负责跟数据库中间进行通信
实验:Django配置MySQL
-
安装数据库服务并且创建数据库
-
(testenv) [root@localhost mysite3]# yum -y install mariadb-server (testenv) [root@localhost mysite3]# systemctl start mariadb (testenv) [root@localhost mysite3]# systemctl enable mariadb (testenv) [root@localhost mysite3]# mysqladmin password New password: 123456 Confirm new password: 123456 (testenv) [root@localhost mysite3]# mysql -uroot -p123456 MariaDB [(none)]> CREATE DATABASE mysite3 DEFAULT CHARSET utf8;
修改 settings.py 文件
-
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 更改数据引擎 'NAME': 'mysite3', # 操作的数据库名称 'USER': 'root', # 连接数据库的用户名 'PASSWORD': '123456', # 连接数据库用户名的密码 'HOST': '127.0.0.1', # 数据库服务所在的主机地址 'PORT': 3306 # 端口号 } }
测试—python3 manage.py migrate
-
(testenv) [root@localhost mysite3]# python3 manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying sessions.0001_initial... OK
什么是模型
-
什么是模型
- 模型是一个 Python 类,它是由 django.db.models.Model 派生出的子类
- 一个模型类代表数据库中的一张数据表
- 模型类中每一个类属性都代表数据库中的一个字段
- 模型是数据交互的接口,是表示和操作数据库的方法和方式
-
models.py
- 模型类写在指定应用 app 的 models.py 模块中
- 建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库
- 根据设计的模型类生成数据库中的表格
- 通过简单的配置就可以进行数据库的切换
缺点
对于复杂业务,使用成本较高 根据对象的操作转换成SQL语句,根据查询的结果转换成对象,在映射过程中由性能损失
映射图
实验:添加模型类
此示例为添加一个 bookstore_book 数据表来存放图书馆中数目的信息
-
添加一个 bookstore 的 app
- python3 manage.py startapp bookstore
-
添加模型类并注册 app
-
# settings.py INSTALLED_APPS = [ # ...... 'bookstore' ]
模型类代码示例:
-
# file: bookstore/models.py from django.db import models class Book(models.Model): title = models.CharField("书名", max_length=50, default="") price = models.DecimalField("定价", max_digits=7, decimal_places=2, default=0.0)
数据库迁移
- 迁移是 Django 同步对模型所做修改(添加模型,删除模型等)到数据库模式的方式
- 生成迁移文件—执行 python3 manage.py makemigrations
- 将应用下的 models.py 文件生成一个中间文件,并保存在 migrations 文件夹中
-
(testenv) [root@localhost mysite3]# python3 manage.py makemigrations Migrations for 'bookstore': bookstore/migrations/0001_initial.py - Create model Book
- 执行迁移脚本程序—执行 python3 manage.py migrate
- 执行迁移程序实现数据迁移,将每个已注册应用下的 migrations 文件夹中的中间文件同步回数据库
-
(testenv) [root@localhost mysite3]# python3 manage.py migrate Operations to perform: Apply all migrations: admin, auth, bookstore, contenttypes, sessions Running migrations: Applying bookstore.0001_initial... OK
查看数据库,验证指定表是否创建成功
-
(testenv) [root@localhost mysite3]# mysql -uroot -p123456 MariaDB [(none)]> USE mysite3; MariaDB [mysite3]> SHOW TABLES; +----------------------------+ | Tables_in_mysite3 | +----------------------------+ | auth_group | | auth_group_permissions | | auth_permission | | auth_user | | auth_user_groups | | auth_user_user_permissions | | bookstore_book | | django_admin_log | | django_content_type | | django_migrations | | django_session | +----------------------------+ MariaDB [mysite3]> DESC bookstore_book; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(50) | NO | | NULL | | | price | decimal(7,2) | NO | | NULL | | +-------+--------------+------+-----+---------+----------------+
创建模型类流程
创建应用
使用
python3 manage.py startapp 应用名称
的方式创建应用,然后要及时的在 settings.py 文件中进行注册在应用下的models.py中编写模型类
- 模型类的类名是数据表名的一部分,建议类名首字母大写
- 类属性名,此名称将作为数据表的字段名
- 字段类型用来映射到数据表中的字段的类型
- 字段选项为这些字段提供附加的参数信息
迁移同步 makemigrations & migrate
模型类修改
任何关于表结构的修改,务必在对应模型类上修改,例:为 bookstore_book 表添加一个名为 info 的字段,类型是 varchar(100),解决方案:
- 模型类中添加对应类属性
- 执行数据库迁移
字段类型
BooleanField() | CharField() |
---|---|
数据库类型:tinyint(1) | 数据库类型:varchar |
编程语言中:使用True或False来表示值 | 注意:必须要指定max_length参数值 |
在数据库中:使用1或0来表示具体的值 | |
DateField() | DateTimeField() |
数据库类型:date 作用:表示日期 | 数据库类型:datetime |
参数(以下参数只能三选一) | 作用:表示日期和时间 |
1.auto_now:每次保存对象时,自动设置该字段为当前时间 | 参数同DateField |
2.auto_now_add:当对象第一次被创建时自动设置当前时间 | FloatField() |
注意:1和2两个选项取值范围(True/False) | 数据库类型:double |
3.default:设置当前时间(取值:字符串格式时间,如:2019-01-01) | 编程语言中和数据库中都使用小数表示值 |
DecimalField() | IntergerField() |
数据库类型:decimal(x, y) | 数据库类型:int |
编程语言中和数据库中:使用小数表示 | 编程语言和数据库中使用字符串 |
参数: | EmailField() |
1.max_digits:位数总数,包括小数点后的位数,该值必须大于等于decimal_places | 数据库类型:varchar |
2.decimal_places:小数点后的数字数量 | 编程语言和数据库中使用字符串 |
字段选项
字段选项,指定创建的列的额外信息,允许出现多个字段选项,多个选项之间使用,隔开
-
primary_key
- 如果设置为True,表示该列为主键,如果指定一个字段为主键,则此数据库不会创建id字段
-
null
- 如果设置为True,表示该列值允许为空
- 默认为 False,如果此选项为 False,建议加入 defalut 选项来设置默认值
-
db_column
- 指定列的名称,如果不指定则采用属性名作为列名
-
verbose_name
- 设置此字段在 admin 界面上的显示名称
-
字段选项样例
-
default
- 设置所在列的默认值,如果字段选项 null=False 建议添加此选项
-
db_index
- 如果设置为 True,表示为该列增加索引
-
unique
- 如果设置为 True,表示该字段在数据库中的值必须是唯一的
模型类-Meta类
使用内部Meta类来给模型赋予属性,Meta类下有很多内建的类属性,可对模型类做一些控制
示例:
练习:修改模型类
-
模型类-Book 表名 book
- title - CharField(50)–书名 唯一
- pub–CharField(100) - 出版社 非空
- price–DecimalField – 图书定价 总位数7/小数点2位
- market_price – 图书零售价 总位数7/小数点2位
-
模型类-Author 表名 author
- name–CharField(11) – 姓名 非空
- age – IntegerField – 年龄 默认值为1
- email – EmailField – 邮箱 允许为空
解决方式
处理方法
问题2:数据库的迁移文件混乱解决办法
解决方案
ORM基本操作
ORM操作
基本操作包括增删改查,即(CRUD操作)
CRUD是指在做计算处理时的增加(create),读取查询(read),更新(update)和删除(delete)
ORM CRUD 核心 -> 模型类.管理器对象
-
修改模型类—bookstore/models.py
-
# file: bookstore/models.py from django.db import models class Book(models.Model): title = models.CharField("书名", max_length=50, default="", unique=True) pub = models.CharField("出版社", max_length=50, default="") price = models.DecimalField("定价", max_digits=7, decimal_places=2, default=0.0) market_price = models.DecimalField("零售价", max_digits=7, decimal_places=2, default=0.0) class Meta: db_table = "book" class Author(models.Model): name = models.CharField("姓名", max_length=11) age = models.IntegerField("年龄", default=1) email = models.EmailField("邮箱", null=True) class Meta: db_table = "author"
数据迁移
-
(testenv) [root@localhost mysite3]# python3 manage.py makemigrations (testenv) [root@localhost mysite3]# python3 manage.py migrate
数据库检测
-
(testenv) [root@localhost mysite3]# mysql -uroot -p123456 MariaDB [(none)]> USE mysite3; MariaDB [mysite3]> SHOW TABLES; | author | | book | MariaDB [mysite3]> DESC author; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(11) | NO | | NULL | | | age | int(11) | NO | | NULL | | | email | varchar(254) | YES | | NULL | | +-------+--------------+------+-----+---------+----------------+ MariaDB [mysite3]> DESC book; +--------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(50) | NO | UNI | NULL | | | price | decimal(7,2) | NO | | NULL | | | market_price | decimal(7,2) | NO | | NULL | | | pub | varchar(50) | NO | | NULL | | +--------------+--------------+------+-----+---------+----------------+
常见问题处理
问题1:当执行 python3 manage.py makemigrations 出现如下迁移错误时的处理方法:
-
对应中文解释:
-
错误原因
- 当对模型类新添加一个字段时可能出现如下错误
- 原理是添加新字段后,数据库不知道原来已有数据对于新建字段该如何赋值,所以新增字段时务必添加default默认值
- 选择1:则会shell中,手动输入一个默认值
- 选择2(推荐):退出当前生成迁移文件过程,修改models.py,新增一个 default=xxx 的缺省值
- 数据库中django_migrations表记录了migrate的全过程,项目各应用中migrate文件应与之对应否则migrate会报错
-
删除所有migrations里所有的000?_xxxx.py(init.py除外)
-
删除数据库
- sql> drop database 自定义项目数据库;
-
重新创建数据库
- sql>CREATE DATABASE自定义项目数据库 DEFAULT CHARSET utf8;
-
重新生成migrations里所有的 000?_xxx.py
- python3 manage.py makemigrations
-
重新更新数据库
- python3 manage.py migrate
管理器对象
每个继承自models.Model的模型类,都会有一个objects对象被同样继承下来,这个对象叫做管理器对象,数据库的增上改查可以通过模型的管理器实现
创建数据
Django ORM 使用一种直观的方式把数据库表中的数据表示成Python对象,创建数据中每一条记录就是创建一个数据对象
方案1
MyModel.objects.create(属性1=值1,属性2=值2,...)
成功:返回创建好的实体对象
失败:抛出异常
方案2:创建MyModel实例对象,并调用save()进行保存
Django Shell
-
在 Django 中提供了一种交互式操作项目叫做 Django Shell,能够在交互模式用项目工程代码执行相应的操作
-
利用 Django Shell 可以代替编写 view 视图层的代码进行直接操作
-
注意:项目代码发生变化时,需要重新进入Django Shell
-
启动方式:
- python3 manage.py shell
实验:使用 Django Shell 添加数据
-
启动 Django Shell(代码发生变化需要重新进入):
-
(testenv) [root@localhost mysite3]# python3 manage.py shell >>>
测试 方案1 后查看数据库:
-
# Django Shell >>> from bookstore.models import Book >>> Book.objects.create(title='Python', pub='清华大学出版社', price=20, market_price=25) <Book: Book object (1)> # mysql MariaDB [mysite3]> select * from book; +----+--------+-------+--------------+-----------------------+ | id | title | price | market_price | pub | +----+--------+-------+--------------+-----------------------+ | 1 | Python | 20.00 | 25.00 | 清华大学出版社 | +----+--------+-------+--------------+-----------------------+
测试 方案2 后查看数据库:
-
# Django Shell >>> from bookstore.models import Book >>> b2 = Book(title='Django', pub='清华大学出版社', price=70, market_price=75) >>> b2.save() # mysql MariaDB [mysite3]> select * from book; MariaDB [mysite3]> select * from book; +----+--------+-------+--------------+-----------------------+ | id | title | price | market_price | pub | +----+--------+-------+--------------+-----------------------+ | 1 | Python | 20.00 | 25.00 | 清华大学出版社 | | 2 | Django | 70.00 | 75.00 | 清华大学出版社 | +----+--------+-------+--------------+-----------------------+