Python学习之旅—Django基础
Posted 不为乌合不从众
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python学习之旅—Django基础相关的知识,希望对你有一定的参考价值。
前言
前段时间业务比较繁忙,没时间更新博客,从这周开始将继续为各位更新博客。本次分享的主题是Django的基础部分,涵盖Django MTV三部分,并通过一个简单的班级管理系统来说明如何使用Django进行开发,好啦,开始今天的主题吧!
一.浅谈MVC、MTV和MVVM
要学习Django,我们很有必要了解下MVC,MTV和MVVM三种模式。
【001】MVC
MVC(Model View Controller 模型-视图-控制器)是一种Web架构的模式(本文不讨论桌面应用的MVC),它把业务逻辑、模型数据、用户界面分离开来,让开发者将数据与表现解耦,前端工程师可以只改页面效果部分而不用接触后端代码,DBA可以重新命名数据表并且只需更改一个地方,无需从一大堆文件中进行查找和替换。MVC模式甚至还可以提高代码复用能力。现在几乎所有的Web开发框架都建立在MVC模式之上。 当然,最近几年也出现了一些诸如MVP, MVVM之类的新的设计模式。 但从技术的成熟程度和使用的广泛程度来讲,MVC仍是主流。
MVC模式的三要素
- Model(数据模型)。是对客观事物的抽象。比如对于学生管理系统而言,学生类就是一个模型。 而一个模型通常还带有很多的和业务相关的逻辑,比如添加,更新,获取学生成绩等等,这些组成了模型的方法。对于开发者模型的表示方法非常易懂和清晰,可以通过非常便捷的代码来做CURD操作而无需写一条又一条的SQL语句。
- View(视图)。呈现给用户的效果,呈现的内容是基于Model,它也是收集用户输入的地方。比如输入用户的ID或者姓名,我们可以在终端页面查看该学生的信息,效果是通过对应的模板和样式把这个数据展示出来。
- Contorller(控制器)。是Model和View之间的沟通者。 因为View中不会对Model作任何操作,Model不会输出任何用于表现的东西,如HTML代码或者某种效果等,它就是点数据。而Contorller用于决定使用哪些Model,对Model执行什么操作,为视图准备哪些数据,是MVC中沟通的桥梁。
MVC的特点是通信单向的:
- 浏览器发送请求
- Contorller和Model交互获取数据
- Contorller调用View
- View渲染数据返回
【002】MTV
和Rails、Spring、Laravel等其他语言的Web框架不一样,在Python的世界中,基本(除了Pylons)都使用了MVC的变种MTV(Model Templates View 模型-模板-视图):
- Model(数据模型)。和MVC的Model一样,处理与数据相关的所有事务:如何存取、如何确认有效性、包含哪些行为以及数据之间的关系等。
- Template(模板)。处理与表现相关的决定:如何在页面或其他类型文档中进行显示出来。
- View。处理业务逻辑,视图就是一个特定URL的回调函数,回调函数中描述数据:从Model取出对应的数据,调用相关的模板。它就是Contorller要调用的那个用来做Model和View之间的沟通函数,从而完成控制。
这里有一点大家要注意区分MVC中的View和MTV中的View:MVC中的View的目的是「呈现哪一个数据」,即它只是负责渲染数据,然后呈现给用户效果;而MTV的View的目的是「数据如何呈现」,说白了,它负责从Model中取出数据,然后调用相关的模板,从而完成对整个流程的控制。
也就是把MVC中的View分成了视图(展现哪些数据)和模板(如何展现)2个部分,而Contorller这个要素由框架自己来实现了,我们需要做的就是把(带正则表达式的)URL对应到视图就可以了,通过这样的URL配置,系统将一个请求发送到一个合适的视图。需要注意,Flask这种微框架就不是一个MVC模式的,因为它没有提供Model,除非集成了SQLAlchemy之类的ORM进来。
二.Web框架本质
对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。当我们在浏览器中输入一个网址时,会发生如下的情况:
- 浏览器查找域名的IP地址
- 这一步包括DNS具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存…
- 浏览器向Web服务器发送一个HTTP请求
- 服务器的永久重定向响应(从 http://example.com 到 http://www.example.com)
- 浏览器跟踪重定向地址
- 服务器处理请求
- 服务器返回一个HTTP响应
- 浏览器显示HTML
- 浏览器发送请求获取嵌入在HTML 中的资源(如图片、音频、视频、CSS、JS等等)
- 浏览器发送异步请求.
基于上面的需求,我们就可以自己实现一个Web框架,在这里我们只需要实现Socket服务端即可。来看下面一段简单到不行的Socket网络编程代码:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((\'127.0.0.1\', 8000))
sock.listen(5)
while True:
conn, addr = sock.accept()
data = conn.recv(8096)
conn.send(b"OK")
conn.close()
可以说Web服务本质上都是在这十几行代码基础上扩展出来的。这段代码就是它们的祖宗。用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定?你这个网站是这个规定,他那个网站按照他那个规定,这互联网还能玩么?所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。这个规则就是HTTP协议,以后你发送请求信息也好,回复响应信息也罢,都要按照这个规则来。这个规则就是HTTP协议,如果你对HTTP协议还不熟悉,可以参考笔者前面的这篇文章。
我们所要做的是让我们的Web服务能够根据用户请求的URL不同而返回不同的内容,同时给浏览器返回HTML源代码,代码如下:
import socket
import pymysql
sk = socket.socket()
sk.bind((\'127.0.01\', 9090))
sk.listen(5)
def get_html_content(file_name):
with open(file_name, encoding=\'utf-8\') as file_obj:
content = file_obj.read()
return content
def get_record():
conn = pymysql.connect(host="127.0.0.1", port=3306, user=\'root\', password=\'cisco\', db="day48", charset=\'utf8\')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select id, name, balance from user")
user_list = cursor.fetchall()
cursor.close()
conn.close()
return user_list
def index():
index_data = get_html_content("index.html")
user_list = get_record()
ret = ""
for item in user_list:
ret += """
<tr>
<td>{0}</td>
<td>{1}</td>
<td>{2}</td>
</tr>
""".format(item[\'id\'], item[\'name\'], item[\'balance\'])
data_new = index_data.replace(\'@@xx@@\', ret)
return data_new
def login():
login_data = get_html_content("login.html")
return login_data
url_func_map = [
("/index", index),
("/login", login)
]
while True:
conn, addr = sk.accept()
data = conn.recv(8096)
header_str = data.decode(\'utf-8\').split(\'\\r\\n\')[0]
request_target = header_str.split(\' \')[1]
func_name = None
for i in url_func_map:
if i[0] == request_target:
func_name = i[1]
break
if func_name:
response = func_name()
else:
response = "404,页面不见了"
conn.send(b"HTTP/1.1 200 OK\\r\\nContent-Type: text/html; charset=utf-8\\r\\n\\r\\n")
conn.send(response.encode(\'utf-8\'))
conn.close()
上述代码模拟了一个web服务的本质.而对于真实开发中的Python Web程序来说,一般分为两部分:服务器程序和应用程序。服务器程序负责对Socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么它们就可以配合使用。一旦标准确定,双方根据约定的标准各自进行开发即可。WSGI(Web Server Gateway Interface)就是这样一种规范,它定义了使用Python编写的Web APP与Web Server之间接口格式,实现Web APP与Web Server间的解耦。
三. Django基础
【001】常用命令如下:
#安装Django,默认会安装最新版本的Django,目前生产环境下最稳定的Django版本是1.8.2,
#因此我们一般指定安装稳定的版本:pip install django==1.8.2
pip3 install django
# 在终端下创建Django项目,名为DjangoProject
$ django-admin startproject mysite
# Django项目环境终端,例如启动Django项目,创建项目中的应用,我们都使用该命令:
$ python manage.py shell
"""
注意如果在终端创建应用程序,我们需要确保此时的路径应该和 manage.py 是同一目录
"""
$ python manage.py startapp student
# 启动django
$ python manage.py runserver # 如果不指定IP地址和端口,默认启动在本机IP 127.0.0.1的8000端口上
$ python manage.py runserver 8080 # 指定启动Django项目的端口8080
# 如果设置IP地址为0.0.0.0,表明局域网中的所有IP地址都可以通过8000端口访问Django项目
$ python manage.py runserver 0.0.0.0:8000
"""
根据当前项目中的模型类来生成数据库脚本,并将脚本映射到数据库中去;
"""
$ python manage.py makemigrations
# 运行应用模型变化到数据库
$ python manage.py migrate
# admin创建管理员用户,按照提示输入用户名和对应的密码就好了邮箱可以留空,用户名和密码必填
$ python manage.py createsuperuser
# 修改用户密码
$ python manage.py changepassword username
【002】Django基本目录结构及作用
mysite/ # 项目的容器,名称自定义
manage.py # 命令行实用工具,以各种方式与该Django项目进行交互
mysite/ # 实际的Python项目
__init__.py # 空文件,导入不出错
settings.py # 这个Django项目配置
urls.py # 这个Django项目的URL声明; 一个Django驱动网站的“目录”
wsgi.py # 一个入口点为WSGI兼容的Web服务器,以满足您的项目
【003】静态文件配置
概述:
静态文件交由Web服务器处理,Django本身不处理静态文件。简单的处理逻辑如下(以nginx为例):
URI请求-----> 按照Web服务器里面的配置规则先处理,以nginx为例,主要求配置在nginx.conf里的location
|---------->如果是静态文件,则由nginx直接处理
|---------->如果不是则交由Django处理,Django根据urls.py里面的规则进行匹配
以上是部署到Web服务器后的处理方式,为了便于开发,Django提供了在开发环境的对静态文件的处理机制。
static配置:
初学者往往会搞不明白STATIC——URL和STATICFILES_DIRS 的区别,如下所示:
STATIC_URL = \'/static/\' # 这是引用名
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"), # 静态文件存放的位置,例如项目中涉及到css,js,image等文件,这里推荐使用
# 列表的形式,要不然可能会报错:ImproperlyConfigured: Your STATICFILES_DIRS setting is not a tuple or list
# 官方文档对此有详细的描述:https://docs.djangoproject.com/en/dev/howto/static-files/;
]
TEMPLATE_DIRS = (os.path.join(BASE_DIR, \'templates\'),)
注意点如下:
必须严格按照static目录下的路径来,也就是说在HTML中引用静态文件,开头必须是/static/目录
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
<link href="/static/lib/sweetalert/sweetalert.css" rel="stylesheet">
如下图所示:
Media型文件在settings.py中的配置:
# in settings:
MEDIA_URL="/media/"
MEDIA_ROOT=os.path.join(BASE_DIR,"app01","media","upload")
# in urls:
from django.views.static import serve
url(r\'^media/(?P<path>.*)$\', serve, {\'document_root\': settings.MEDIA_ROOT}),
\'\'\'
静态文件的处理又包括STATIC和MEDIA两类,这往往容易混淆,在Django里面是这样定义的:
MEDIA:指用户上传的文件,比如在Model里面的FileFIeld,ImageField上传的文件。如果你定义
MEDIA_ROOT=c:\\temp\\media,那么File=models.FileField(upload_to="abc/")#,上传的文件就会被保存到c:\\temp\\media\\abc
eg:
class blog(models.Model):
Title=models.charField(max_length=64)
Photo=models.ImageField(upload_to="photo")
上传的图片就上传到c:\\temp\\media\\photo,而在模板中要显示该文件,则在这样写
在settings里面设置的MEDIA_ROOT必须是本地路径的绝对路径,一般是这样写:
BASE_DIR= os.path.abspath(os.path.dirname(__file__))
MEDIA_ROOT=os.path.join(BASE_DIR,\'media/\').replace(\'\\\\\',\'/\')
MEDIA_URL是指从浏览器访问时的地址前缀,举个例子:
MEDIA_ROOT=c:\\temp\\media\\photo
MEDIA_URL="/data/"
在开发阶段,media的处理由django处理:
访问http://localhost/data/abc/a.png就是访问c:\\temp\\media\\photo\\abc\\a.png
在模板里面这样写<img src="/media/abc/a.png">
在部署阶段最大的不同在于你必须让web服务器来处理media文件,因此你必须在web服务器中配置,
以便能让web服务器能访问media文件
以nginx为例,可以在nginx.conf里面这样:
location ~/media/{
root/temp/
break;
}
具体可以参考如何在nginx部署django的资料。
\'\'\'
【004】视图层之路由配置系统(views)
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
url(正则表达式, views视图函数,参数,别名),
] 参数说明: 一个正则表达式字符串 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串 可选的要传递给视图函数的默认参数(字典形式) 一个可选的name参数
来看下面的例子:
urlpatterns = [
url(r\'login.html/\', views.login, name="login")]
r\'login.html/\'表示匹配用户在浏览器中请求访问的URL地址,通常配合正则表达式进行精确匹配;
views.login表示一旦匹配到前面指定的地址,就执行这里的视图函数,login是views.py文件中的视图函数,一般会有
多个函数存在于views.py文件中,通常情况下,一般使用在指定应用的目录的urls.py文件下,导入,例如我新建了一个
应用app01,在它下面的urls.py文件中,我们定义具体url和函数的对应关系:
# 先导入具体的包,然后再指定具体url和视图函数的对应关系
from app01 import views
url(r\'login.html/\', views.login, name="login")
name属性取别名。
来看如下的具体需求:
1.通常在form表单中,我们往往使用post方法向服务器传递数据,同时要指定哪个url地址来处理数据,我们往往
采用硬编码的形式将路径写死:
<form action="/login/" method="post">
{% csrf_token %}
<p>姓名:<input type="text" name="name"> </p>
<p>密码:<input type="password" name="pwd"> </p>
<p><input type="submit" name="提交"> </p>
</form>
上面的需求表示我们将用户输入的数据交给/login/处理,
现在有20个这样的需求,都是交给/login/处理,但是突然由于业务变动,我们想将
用户输入的数据交给应用app01下面的login.html,即处理地址变为:app01/login.html,
按照我们硬编码的方式,那就要重新修改上述20个函数,是不是太麻烦了!!此时就可以用到
name属性了,我们可以将form表单中的action属性设置为jinja2的模板形式:
action="{% url "login" %}",采用url指定地址即可,url后面是别名,这样,在后台urls.py中,我们
可以设置name属性,其值为这里的别名:login,例如:
url(r\'login.html/\', views.login, name="login")
这样设置后,凡是用户端能够匹配到r\'login.html/\'这个正则表达式的url,我都采用login函数处理,并且将
login.html模板文件中的action地址替换为:app01/login.html,我们来看实际的运行效果:
以上我们称之为url的反向解析。下面通过实际例子分析name参数和include参数的作用
分析:用户在浏览器中输入:http://127.0.0.1:8090/app01/login.html/;首先到
与Django同名的app目录的urls.py文件中匹配:
url(r\'app01/\', include(\'app01.urls\')匹配到第二条,这里我们来插播一个新的关键字参数include。
还记得我们开始创建Django项目时,会把所有与业务相关的url和视图函数的匹配关系全部都放到urls.py文件中,如下
所示:
urlpatterns = [
url(r\'^teacher_list/\', teacher_list),
url(r\'^add_teacher/\', add_teacher),
url(r\'^delete_teacher/\', delete_teacher),
url(r\'^modal_teacher_list/\', modal_teacher_list),
url(r\'^modal_edit_teacher/\', modal_edit_teacher),
url(r\'^class_list/\', class_list),
url(r\'^add_class/\', add_class),
url(r\'^delete_class/\', delete_class),
url(r\'^edit_class/\', edit_class),
]
这只是我们学习时候的案例,在现实生产环境中,往往对应上百条的url,肯定不能全都写到url.py文件中,理由
有2点,如果一个url和视图函数的对应关系写错了,那么其他应用都运行不了,这就造成了严重的耦合,另外为了
保证应用之间的独立性,让它们互不影响,我们也不应该让它们都放在一起。于是出现了include关键字,也即路由分发策略
拿我们刚才的例子来说:
url(r\'app01/\', include(\'app01.urls\'),用户输入:http://127.0.0.1:8090/app01/login.html/
首先匹配到app01,然后执行后面的视图函数,当遇到include关键字,此时相当于告诉Django你去include
里面的参数地址中寻找视图函数,此时Django会去应用app01中的urls.py文件中去寻找视图函数,内容如下:
urlpatterns = [
url(r\'login.html/\', views.login, name="login"),
url(r\'index.html/\', views.index)
]
到达app01.urls.py文件中,继续拿用户剩下的地址login.html/进行匹配,因此会首先匹配到第一条正则表达式,于是
执行后面的视图函数login,这里由于我们设置了url反向解析,因此模板文件中使用url进行反向解析的实际地址会被替换为
前面正则表达式匹配到的路径:login.html。从运行效果可以看到,action中的路径是绝对路径,即,action的实际地址是
/app01/login.html/。到此为止,我们总算讲完了这几个关键字参数。
【005】URL具体配置规则
from django.conf.urls import url
from . import views
urlpatterns = [
url(r\'^articles/2003/$\', views.special_case_2003),
url(r\'^articles/([0-9]{4})/$\', views.year_archive),
url(r\'^articles/([0-9]{4})/([0-9]{2})/$\', views.month_archive),
url(r\'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$\', views.article_detail),
]
上面是一些具体的匹配例子,我们来看如下几个需要注意的点:
NOTE:
1 URL一旦匹配成功则不再继续往下面匹配;
2 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号;例如url(r\'^articles/([0-9]{4})/$\', views.year_archive),
我们在[0-9]{4}加入了(),表示我们想从这个url中捕获任意一个4位整数
3 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
4 每个正则表达式前面的\'r\'是可选的但是建议加上。
一些请求的例子:
/articles/2005/3/ 不匹配任何URL模式,因为列表中的第三个模式要求月份应该是两个数字。
/articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。
/articles/2005/03/ 请求将匹配列表中的第三个模式。Django 将调用函数
views.month_archive(request, \'2005\', \'03\')。关于调用函数的传参问题,我们将在下面一节中详细描述。
【006】2.1.2 有名分组(named group)
下面我们来看有名分组的几个例子:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r\'^articles/2003/$\', views.special_case_2003),
url(r\'^articles/(?P<year>[0-9]{4})/$\', views.year_archive),
url(r\'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$\', views.month_archive),
url(r\'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$\', views.article_detail),
]
这个实现与我们前面的例子几乎没有太大区别,但细心的同学可能已经发现了,在捕获具体值得时候,我们加上了
?P<year>,例如url(r\'^articles/(?P<year>[0-9]{4})/$\', views.year_archive),我们在[0-9]{4} 加上了(?P<year>)
这表示我们为捕获到的值取一个名字year,并将该值以关键字传参的形式传递给后面的函数views.year_archive。
例如让地址 /articles/2005/03/ 去匹配上述的url地址,匹配成功后,我们将调用views.month_archive(request, year=\'2005\', month=\'03\')函数;
再例如:articles/2003/03/03/ ,请求将调用函数views.article_detail(request, year=\'2003\', month=\'03\', day=\'03\') 。
通过对比上面的示例可知,使用(?p<关键字名称>)捕获的值将作为关键字参数而不是位置参数传递给视图函数。
【007】URLConf在什么上查找
URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。
例如,http://www.example.com/myapp/ 请求中,URLconf 将查找myapp/。
在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/。
URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POST、GET、HEAD等等 —— 都将路由到相同的函数。
【008】每个捕获的参数都作为一个普通的Python 字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:
url(r\'^articles/(?P<year>[0-9]{4})/$\', views.year_archive)
views.year_archive() 的year 参数将是一个字符串
【009】指定视图参数的默认值
# URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
url(r\'^blog/$\', views.page),
url(r\'^blog/page(?P<num>[0-9]+)/$\', views.page),
]
# View (in blog/views.py)
def page(request, num="1"):
在上面的例子中,两个URL模式指向同一个视图views.page —— 但是第一个模式不会从URL 中捕获任何值。如果第一个模式匹配,
page() 函数将使用num参数的默认值"1"。如果第二个模式匹配,page() 将使用正则表达式捕获的num 值。
三. 视图层
视图层主要负责处理用户的请求并返回响应。返回的内容可以是HTML内容的网页,或重定向,或404错误,或一个XML文件,或一个形象,字符串等等。
在Django中,http请求会产生两个核心对象:http请求:HttpRequest对象 http响应:HttpResponse对象 所在位置:django.http,下面我们分别来梳理下HttpRequest和HttpResponse的一些重点属性和方法:
#从django.http模块中导入HttpResponse类[1]
from django.http import HttpResponse
import datetime
def current_datetime(request): #[2]
now=datetime.datetime.now()
html="<html><body>现在时刻:%s.</body></html>" %now
return HttpResponse(html)
# 注意:这是一段很简单、简陋的例子
# 在这个(views.py)视图中每一个函数称作视图函数,视图函数都以一个HttpRequest对象为第一个参数,该参数通常命名为request,注意这里的参数也可以命名为其他的名称,只是request
这个名称能够做到见名知意。
由上面示例得到视图函数第一个参数是一个HttpRequest对象,那么通过这个对象可以拿到一些信息,如下:
A:HttpRequest
【01】HttpRequest对象中的常见属性:
1.HttpRequest.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
另外,我们还可以用 python 的类文件方法去操作它,详情参考 HttpRequest.read() 。
2.HttpRequest.path
一个字符串,表示请求的路径组件(不含域名),例如我们在浏览器中输入访问地址:127.0.0.1:8000/music/bands/the_beatles/
HttpRequest.path得到的路径就是:"/music/bands/the_beatles/"
3.HttpRequest.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
例如:"GET"、"POST"
4.HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 \'utf-8\')。
这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
5.HttpRequest.GET
一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
例如我们在浏览器中输入访问地址:127.0.0.1:8000/student_list/?edit_id=3 表示我们想编辑的学生ID号为3
在视图函数中,可以使用request.GET.get(\'edit_id\')获取ID值3,从而方便我们去数据库中修改。
6.HttpRequest.POST
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
因此,不应该使用 if request.POST 来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
我们通常使用该属性来获取用户在输入框中的用户名和密码等信息,例如:
username = request.POST.get(\'username\')
password = request.POST.get(\'password\')
另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
7.HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串,例如获取服务端发送的cookies值:
request.COOKIES.get("login1") 只要存在该cookie,那么证明用户处于登入状态。
8.HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
包含数据。否则,FILES 将为一个空的类似于字典的对象。
9.HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
完整的细节参见会话的文档。例如我们一般使用request.session.get(\'key\')获取对应的value值
注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,例如一个用户可能有多个爱好,那么当我们使用
select标签返回数据给后台时是一个列表,此时后台应该使用request.POST.getlist("hobby")
【02】HttpRequest对象的常用方法
1.HttpRequest.get_full_path()
返回 path,如果可以将加上查询字符串。
例如:"/music/bands/the_beatles/?print=true"
2.HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt=\'\', max_age=None)
返回签名过的Cookie 对应的值,如果签名不再合法则返回django.core.signing.BadSignature。
如果提供 default 参数,将不会引发异常并返回 default 的值。
可选参数salt 可以用来对安全密钥强力攻击提供额外的保护。max_age 参数用于检查Cookie 对应的时间戳以确保Cookie 的时间不会超过max_age 秒。
复制代码
>>> request.get_signed_cookie(\'name\')
\'Tony\'
>>> request.get_signed_cookie(\'name\', salt=\'name-salt\')
\'Tony\' # 假设在设置cookie的时候使用的是相同的salt<以上是关于Python学习之旅—Django基础的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin学习之旅解决错误:kotlin.NotImplementedError: An operation is not implemented: Not yet implemented(代码片段