Python之Django框架[1]
引入
Web框架是帮助服务器处理动态请求的应用程序。
服务器接收到http请求报文后,首先判断它请求的资源是静态资源还是动态资源。如果是静态资源,服务器就直接组合响应报文返回对应资源。
如果是动态资源,服务器就将http请求报文打包成WSGI协议格式的数据,转交给Web框架。
Web框架得到请求路径等信息,自动路由到对应处理函数,组装静态文件和数据,返回给服务器。
服务器得到处理后的数据,组装响应报文,返回给请求方。
总而言之,web框架的基本功能:
- 接收数据
- 处理数据
- 返回数据
前人已经搭建了许许多多的web框架,它们都能自动实现以上流程,使得程序员们不再需要关心具体细节,而是更多地去关注处理逻辑。
Django简介
Django,发音为[`dʒæŋɡəʊ],是用python语言写的开源web开发框架,并遵循MVC设计。
劳伦斯出版集团为了开发以新闻内容为主的网站,而开发出来了这个框架,于2005年7月在BSD许可证下发布。如今,Django框架已经能够胜任处理大部分Web应用程序的任务了。
Django被设计出来的主要目的是简便、快速地开发数据库驱动的网站。
特点
Django是一个重量级框架,它能支持大量的操作,内容丰富:
- 提供项目工程管理的自动化脚本工具
- 数据库ORM支持(对象关系映射,英语:Object Relational Mapping)
- 模板
- 表单
- Admin管理站点
- 文件管理
- 认证权限
- session机制
- 缓存
MVC设计
MVC设计模式的核心思想是分工、解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容。
M:Model-----模型
指从现实世界中抽象出来的对象模型,是应用逻辑的反应;它封装了数据和对数据的操作,是实际进行数据处理的地方(模型层与数据库才有交互)。主要负责数据处理
V:Viem-----视图
是应用和用户之间的接口,它负责将应用显示给用户 和 显示模型的状态。主要负责页面显示
C:Controller------控制器
控制器负责视图和模型之间的交互,控制对用户输入的响应、响应方式和流程;它主要负责两方面的动作,一是把用户的请求分发到相应的模型,二是吧模型的改变及时地反映到视图上。主要负责过程控制
在Web开发中,
-
Model主要封装对数据库层的访问,对数据库中的数据进行增、删、改、查操作。
-
View用于封装结果,生成页面展示的html内容。
-
Controller用于接收请求,处理业务逻辑,与Model和View交互,返回结果。
Django MVT设计
Django的MVT设计是MVC设计的变形
- M,Model,模型,与MVC中的M功能相同,负责和数据库交互,进行数据处理。
- V,View,视图,与MVC中的C功能相同,接收请求,进行业务处理,返回应答。
- T,Template,模板,与MVC中的V功能相同,负责封装构造要返回的html。
虚拟环境
环境指的是程序编写和运行所依赖的解释器和库文件。
一般,Python程序的运行环境是全局环境。即所有Python程序都使用同一个环境。
这样会产生很多问题:
各个程序所需要的解释器、包或模块的版本号不同怎么办?
除了重复安装卸载外,搭建虚拟环境是一个很好的解决办法。
虚拟环境指的是给项目创建一个"与世隔绝"的运行环境。这样,各个项目的运行环境就能够互不干扰。
搭建方法
Linux
#安装所需要的模块
sudo pip install virtualenv
sudo pip install virtualenvwrapper
#创建虚拟环境保存地
mkdir $HOME/.virtualenvs
# 打开~/.bashrc文件,添加环境变量:
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
#激活环境变量
source ~/.bashrc
#创建虚拟环境(解释器和pip);创建完默认直接进入
mkvirtualenv -p python3 env_name
#进入虚拟环境后安装指定版本包或模块
pip install django==1.11.11
#查看所有虚拟环境
workon
#使用虚拟环境env_name
workon env_name
#退出虚拟环境
deactivate
#删除虚拟环境env_name
rmvirtualenv env_name
Windows
#安装所需要的模块
pip install virtualenv
pip install virtualenvwrapper
#创建一个文件夹保存虚拟环境
mkdir my_virtualenvs
#创建虚拟环境(解释器和pip)
virtualenv env_name
#启动虚拟环境
env_name\scripts\activate
#进入虚拟环境后会出现小括号
(env_name): pip install django==1.11.11
#退出虚拟环境
deactivate
Django项目
创建项目
django-admin startproject project_name
- 创建项目project_name
创建成功后,项目结构如下:
-
manage.py
:一个能进行各种操作的脚本 -
asgi.py
:ASGI配置文件,即异步的(Async)WSGI -
setting.py
:项目总的配置文件 -
urls.py
:URL匹配相关配置文件 -
wsgi.py
:WSGI配置文件
运行调试服务器
python manage.py runserver ip:port
#默认为localhost:8000
python manage.py runserver
打开浏览器输入对应ip地址和端口号即可实时查看页面效果
Ctrl C
停止运行
子应用
子应用是一个个功能独立的模块。如:登录、注册、支付…
创建子应用,不仅可以保持模块间的独立,而且还方便以后的项目复用。
python manage.py startapp sub_app
- 创建子应用sub_app
如
python manage.py startapp lookup
创建成功后,子应用结构:
admin.py
:与网站的后台管理相关apps.py
:当前子应用的相关配置migrations
:存放数据库迁移历史文件models.py
:数据模型相关tests.py
:开发测试相关views.py
:动态清楚处理的视图相关
子应用注册
子应用只有安装注册后才能被项目使用。
注册安装子应用只需在settings.py
中的INSTALLED_APPS
列表内添加新的子应用的apps.py
文件中xxxConfig
类。
如子应用名是lookup,就应该添加lookuo.apps.LookupConfig
类(这个类系统自动生成)
子应用设置
子应用创建之后,在app.py
中会自动生成xxxConfig
类:
from django.apps import AppConfig
class LookupConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'lookup'
我们可以在这里添加一些其他的设置。
比如,verbose_name
,是子应用在后台上显示的名字。
from django.apps import AppConfig
class LookupConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'lookup'
verbose_name="书籍与作者查询"
模型Models
子应用的models.py
负责与数据库进行交互
数据库设置
在项目的settings.py
文件中,可以修改数据库相关设置。
Django默认使用splite数据库:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
可以修改为其他数据库,如MySQL.
首先安装所需模块:
pip install pymysql
其次在与项目文件夹同名的子文件夹中的__init__
文件中添加导入安装语句
import pymysql
pymysql.install_as_MySQLdb()
最后修改settings.py
文件中的数据库配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # mysql引擎
'HOST': '127.0.0.1', # 数据库主机地址
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': '123', # 数据库用户密码
'NAME': 'library_system' # 数据库名字
}
}
ORM模式
Django将与数据库交互的各种操作封装成了ORM模式。
即对象关系映射(Object Relational Mapping,简称ORM)模式
数据表----------->模型类
数据行----------->对象/实例
字段 -------------->属性
即,程序员通过ORM模式进行逻辑层次的面向对象的编程,Django框架负责自动把这些操作转化为sql语句,并与对应数据库(可能种类不同)交互。
这样的话,程序员就不用关心底层细节,实现了数据库操作的抽象化与简单化。
数据库迁移
设计表-----定义模型类
在子应用的models.py
中可以定义子应用需要用到的模型类。[模型类
→
\rightarrow
→数据表]
- 这些模型类都需继承自
models.Model
创建字段就是在类中创建属性。[模型类属性 → \rightarrow →数据表字段]
- 这些属性的创建需要用到
models
中的API类。一般格式为类型大写+Filed
,如CharFiled
类名 | 说明 |
---|---|
AutoField | 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性 |
BooleanField | 布尔字段,值为True或False |
NullBooleanField | 支持Null、True、False三种值 |
CharField | 字符串,参数max_length表示最大字符个数 |
TextField | 大文本字段,一般超过4000个字符时使用 |
IntegerField | 整数 |
DecimalField | 十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数 |
FloatField | 浮点数 |
DateField | 日期, 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误 |
TimeField | 时间,参数同DateField |
DateTimeField | 日期时间,参数同DateField |
FileField | 上传文件字段 |
ImageField | 继承于FileField,对上传的内容进行校验,确保是有效的图片 |
- 创建字段属性时,还可以添加一些选项和限制:
选项 | 说明 |
---|---|
null | 如果为True,表示允许为空,默认值是False |
blank | 如果为True,则该字段允许为空白,默认值是False |
db_column | 字段的名称,如果未指定,则使用属性的名称 |
db_index | 若值为True, 则在表中会为此字段创建索引,默认值是False |
default | 默认值 |
primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用 |
unique | 如果为True, 这个字段在表中必须有唯一值,默认值是False |
verbose_name | 用于在后台等地方显示,便于读懂和操作 |
- 设置外键通过
models.ForeignKey()
,第一个参数是外键关联到的表的字段,还可以传入on_delete
属性规定主表数据删除后外键表的行为:
on_delete可选值 | 行为 |
---|---|
models.CASCADE | 级联,删除主表数据时连同外键表中数据一起删除 |
models.PROTECT | 保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据 |
models.SET_NULL | 设置为NULL,仅在该字段null=True允许为null时可用 |
models.SET_DEFAULT | 设置为默认值,仅在该字段设置了默认值时可用 |
models.SET(…) | 设置为特定值或者调用特定方法 |
models.DO_NOTHING | 不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常 |
- 还可以在模型类中重写
Meta
类和__str_
,以实现某些小功能(详见官方文档)
下面以图书管理系统为例:
from django.db import models
# Create your models here.
class Writers(models.Model):
"""定义作者模型----作者表"""
id = models.AutoField(verbose_name="作家编号", primary_key=True)
name = models.CharField(max_length=30, verbose_name="姓名")
birth = models.DateField(verbose_name="出生日期")
country = models.CharField(max_length=20, verbose_name="国家")
introduction = models.CharField(max_length=300,verbose_name="简介")
class Meta:
"""元数据"""
db_table = "writers_info" # 迁移后建立的数据表名称
verbose_name = "作家" # 后台显示的名称
def __str__(self):
"""数据项显示的内容"""
return f"{self.name} {self.country}"
class Books(models.Model):
"""定义书籍模型----书籍表"""
id = models.AutoField(verbose_name="书籍编号", primary_key=True)
name = models.CharField(max_length=20, verbose_name="名称")
price = models.DecimalField(decimal_places=2,max_digits=5,verbose_name="价格")
writer = models.ForeignKey(Writers, on_delete=models.CASCADE,verbose_name="作者编号")
out_time = models.DateField(verbose_name="出版时间")
introduction = models.CharField(max_length=300,verbose_name="简介")
class Meta:
"""元数据"""
db_table = "books_info" # 迁移后建立的数据表名称
verbose_name = "书籍" # 后台显示的名称
def __str__(self):
"""数据项显示的内容"""
return f"{self.name} {self.writer.name}"
生成表----模型类迁移转化到具体数据库中
定义好模型类后,在终端中进行迁移的操作:
#生成迁移文件-----xxxx_initial.py
python manage.py makemigrations
#迁移----同步数据库
python manage.py migrate
Django框架会在迁移文件中准备好一切关于数据库的配置,迁移之后,模型类就会在配置好的数据库中真正地变成数据表。
如下图,在数据库中自动创建了包括book_info和writers_info在内的一系列表
Admin站点管理
修改本地化配置
在settings.py
中可以修改网站的时区和语言
默认:
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'en-us' #英语
TIME_ZONE = 'UTC' #世界协调时间
可以修改为:
LANGUAGE_CODE = 'zh-Hans' #汉字
TIME_ZONE = 'Asia/Shanghai' #上海时区
创建管理员
python manage.py createsuperuser
- 按照提示输入用户名,邮箱,密码即可
重置密码:
python manager.py changepassword username
模型类注册
需要在子应用的admin.py
文件导入模型类并注册,我们才能够在后台进行相关模型的数据库操作
from django.contrib import admin
# Register your models here.
from lookup.models import Books,Writers
admin.site.register(Books)
admin.site.register(Writers)
登录站点
启动服务器,登录http://ip:port/admin
。如:http://127.0.0.1:8000/admin
在此进行的数据库操作会保存更新。
视图与URL
视图函数
视图是一个处理用户请求的函数。这个函数需要在views.py
中定义。
视图函数的第一个参数预留给HttpRequest
类的对象reqeust
。request
在调用时包含用户的各种请求信息。
视图函数的返回值需要是一个HttpResponse
类的对象。故需要导入HttpResponse
模块 :
from django.http import HttpResponse
视图函数的内部由业务逻辑决定。一般要通过模型访问数据库得到数据,并替换模板html文件中预设的变量,组合成动态网页返回。
如简简单单的返回一句话:
# Create your views here.
def books_info(request):
"""书籍挑选页面"""
return HttpResponse("Here are all the books.")
def student_info(request):
"""作家简介页面"""
return HttpResponse("Here are all the writers.")
配置URL匹配路由
用户的请求URL(去掉ip,port,和请求参数)是一步一步与我们自己设置的URL匹配的。
首先是所有URL匹配机制的源头-----项目同名文件夹中的settings.py
默认的有这么一行。
指明了匹配的第一步
ROOT_URLCONF = 'LibrarySystem.urls' #URL设置
匹配的的第一步,就是项目相同文件夹中的urls.py
中的urlpatterns
列表
urlpatterns = [
path('admin/', admin.site.urls),
]
默认的这一行代码的意思是:如果请求URL以admin/开头,继续进入admin.site.urls
中进行匹配。
实际上,我们的admin站点的那些网页的url就默认生成在admin.site.urls
中。
我们可以在这个列表中添加path(正则表达式模式字符串,include(子应用.urls) )
来将URL匹配引向子应用。(需要导入include;需要在子应用文件夹中创建urls.py
)
如:
from django.contrib import admin
from django.urls import path
from django.conf.urls import include
urlpatterns = [
path('admin/', admin.site.urls), #依次往下
path('lookup/',include('lookup.urls')) #以lookup开头就导向lookup.urls中的urlpatterns
]
经过主文件夹的引流,匹配的阵地转移到子应用文件夹中我们创建的urls.py
.
from django.urls import path
from lookup.views import books_info,writers_info
urlpatterns = [
path('books/', books_info), #匹配/lookup/books/,交给books_info视图函数处理
path('writers/', writers_info) #匹配/lookup/writers/,交给writers_info处理
]
静态文件与模板文件
我们把所有静态文件和模板分别放至新创建的文件夹staic
,templates
中
静态文件配置
在settings.py
中修改设置以下两个值
import os
# 静态文件url
STATIC_URL = '/static/'
# 静态文件目录
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
- 这样就可以通过
http://ip:port/static/...
来访问static
目录中的静态文件了
动态模板文件配置
在settings.py
中修改设置’DIR’项为模板文件目录
import os
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS':[os.path.join(BASE_DIR, 'templates')], #修改模板文件目录
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
编写模板文件
模板文件大部分是需要进行数据替换的html文件。
我们可以使用以下语法在html文件中中添加占位变量和语句。
#占位变量
{ {var_name} }
#for循环
{% for item in items %}
....
{% endfor %}
#if语句
{% if condition1 %}
...
{% elif condition2 %}
...
{% else condition3 %}
...
{% endif %}
如:
我们可以在templates文件夹中为lookup添加info.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ topic }}</title>
</head>
<body>
<table>
<caption>{{ topic }}</caption>
<tr>
{% for head in heads %}
<th>{{ head }}</th>
{% endfor %}
</tr>
{% for row in rows %}
<tr>
{% for item in row %}
<td>{{ item }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</body>
</html>
使用模板文件结合数据模型编写视图
我们可以导入render函数,以其返回值-----一个HttpResponse
对象,来作为视图函数的返回值
render函数接受三个参数,第一个是请求对象request
,第二个是模板文件的路径(相对templates),第三个是context字典-----即要替换模板文件中的占位变量的key-value组成的字典。
为了准备好context
字典,我们可以对模型类进行增删查改操作,以获得对应数据。
数据模型增删查改
以下操作(除导入)在view.py
的视图函数中进行
from lookup.models import Books #导入模型类
"""增加数据"""
#方法1
#创建模型类实例-----映射数据行
newbook=Books(name="倚天屠龙记",price=42,writer=2,out_time="1961/01/01")
#保存到数据库中
newbook.save()
#方法2
#直接通过model.objects的方法
Books.objects.create(name="倚天屠龙记",price=42,writer=2,out_time="1961/01/01")
"""修改数据"""
#方法1
#查询以获得对象(数据行)
book=Books.objects.get(name='倚天屠龙记')
#直接修改查询到的对象的属性
book.out_time="1961/01/02"
#保存到数据库中
book.save()
#方法2
#fliter查询对象,update更新数据
Books.objects.filter(name='倚天屠龙记').update(out_time="1961/01/02")
"""删除数据"""
#方法1
book=Books.objects.get(name='倚天屠龙记')
person.delete()
#方法2
Books.objects.filter(name='倚天屠龙记').delete()
"""查询数据"""
#查询满足某条件的一个数据行
Books.objects.get(condition)
#查询所有数据行
Books.objects.all()
#查询满足某条件的多个数据行
Books.objects.fliter(condition)
#查询不满足条件的多个数据行
Books.objects.exclude(condition)
其中,查询时的condition的格式是
属性__运算符或限制=值
如
Books.objects.filter(id__exact=1) #id准确地等于1
Books.objects.filter(name__contains='传') #name里含有“传”
Books.objects.filter(name__endswith='传') #name以"传"结尾
Books.objects.filter(name__startswith='射') #name以“射”开头
Books.objects.filter(introdunction__isnull=True) #名字为NULL
Books.objects.filter(id__in=[1,3,5]) #id在1,3,5范围中
Books.objects.filter(id__gt=3) #greater than,大于
Books.objects.filter(id__gte=3) #greater than and equal,大于等于
Books.objects.filter(id__lt=3) #less than,小于
Books.objects.filter(id__lte=3) #less than and equal,小于等于
Books.objects.filter(birth_year|birth_month|birth_day|birth_week_day|birth_hour|birth_minute|birth_second=...) #特定日期
编写视图
利用查询到的模型对象,我们可以替换模板html文件中的占位变量,并用render渲染返回。
如:
def books_info(request):
"""书籍挑选页面"""
books_data = Books.objects.all()
context = {"topic": "书籍挑选", "heads": ["名称", "作者", "价格", "出版时间"], "rows": []}
for book in books_data:
context["rows"].append([book.name,book.writer.name,book.price,book.out_time])
print(context)
return render(request,"lookup/info.html",context)
替换占位变量后,最后的显示效果是这样的: