视图层
一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。
- 每个视图函数都使用
HttpRequest
对象作为第一个参数,并且通常称之为request
。 - 每个视图函数都负责返回一个
HttpResponse
对象。,其中包含生成的响应
CBV和FBV
FBV(基于函数的视图):面向函数式编程
CBV(基于类的视图):面向对象式编程
FBV
# FBV版添加班级
def add_class(request):
if request.method == "POST":
class_name = request.POST.get("class_name")
models.Classes.objects.create(name=class_name)
return redirect("/class_list/")
return render(request, "add_class.html")
CBV
get请求来就会走get方法,post请求来就会走post方法
# CBV版添加班级
from django.views import View
class AddClass(View):
def get(self, request):
return render(request, "add_class.html")
def post(self, request):
class_name = request.POST.get("class_name")
models.Classes.objects.create(name=class_name)
return redirect("/class_list/")
使用CBV时,urls.py中也要做对应的修改:
path('add_class/', views.AddClass.as_view()),
Request和Response对象
Request对象
当一个页面被请求时,Django就会创建一个包含本次请求原信息的HttpRequest对象。Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。
请求相关的常用值
-
path_info 返回用户访问的url,不包括域名
-
method 请求中使用的HTTP方法的字符串表示,全大写表示。
-
GET 包含所有HTTP GET参数的类字典对象
-
POST 包含所有HTTP POST参数的类字典对象
-
body 请求体,byte类型,request.POST的数据就是从body中提取到的
属性
django将请求报文中的请求行、头部信息、内容主体封装成 HttpRequest 类中的属性。除了特殊说明的之外,其他均为只读的。
0.HttpRequest.scheme 表示请求方案的字符串(通常为http或https)
1.HttpRequest.body 一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML、Json等。但如果要处理表单数据推荐还是使用 HttpRequest.POST。另外还可以用 python 的类文件方法去操作它,详情参考HttpRequest.read()
2.HttpRequest.path 一个字符串,表示请求的路径组件(不含域名),例如:"/music/bands/the_beatles/"。request.get_full_path() 后缀和参数全部获取
def index(request):
print(request.path) # /music/bands/the_beatles/
print(request.get_full_path()) # /music/bands/the_beatles/?id=1&name=jason
return HttpResponse("index")
3.HttpRequest.method 一个字符串,表示请求使用的HTTP方法。必须使用大写。例如:"GET"、"POST"
4.HttpRequest.encoding 一个字符串,表示提交数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。这个属性是可写的,可以修改它来修改访问表单数据使用的编码
5.HttpRequest.GET 一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象
6.HttpRequest.POST 一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。因此,不应该使用 if request.POST 来检查使用的是否是POST方法;应该使用 if request.method == "POST"。另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
7.HttpRequest.COOKIES 一个标准的Python字典,包含所有的cookie。键和值都为字符串
8.HttpRequest.FILES 一个类似于字典的对象,包含所有的上传文件信息。FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST且提交的<form>带有enctype="multipart/form-data" 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象
9.HttpRequest.META 一个标准的Python字典,包含所有的HTTP首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送的HTTP Host头部。
HTTP_REFERER —— Referring页面。
HTTP_USER_AGENT —— 客户端的user-agent字符串。
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_ 前缀。所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键
10.HttpRequest.user 一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。例如:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
匿名用户:class models.AnonymousUser,django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True而不是False。
is_authenticated() 返回False而不是True。
set_password()、check_password()、save()和delete()引发 NotImplementedError。
New in Django 1.8: 新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
11.HttpRequest.session 一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django启用会话的支持时才可用。
方法
1.HttpRequest.get_host() 根据从HTTP_X_FORWARDED_HOST(如果打开 USE_X_FORWARDED_HOST,默认为False)和 HTTP_HOST 头部信息返回请求的原始主机。如果这两个头部没有提供相应的值,则使用SERVER_NAME 和SERVER_PORT,在PEP 3333 中有详细描述
USE_X_FORWARDED_HOST:一个布尔值,用于指定是否优先使用 X-Forwarded-Host 首部,仅在代理设置了该首部的情况下,才可以被使用。注意:当主机位于多个代理后面时,get_host() 方法将会失败。除非使用中间件重写代理的首部。
2.HttpRequest.get_full_path() 返回 path,将加上查询字符串。例如:"/music/bands/the_beatles/?print=true";HttpRequest.path 返回 path不包括查询字符串
3.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
>>> request.get_signed_cookie('non-existing-cookie')
...
KeyError: 'non-existing-cookie' # 没有相应的键时触发异常
>>> request.get_signed_cookie('non-existing-cookie', False)
False
>>> request.get_signed_cookie('cookie-that-was-tampered-with')
...
BadSignature: ...
>>> request.get_signed_cookie('name', max_age=60)
...
SignatureExpired: Signature age 1677.3839159 > 60 seconds
>>> request.get_signed_cookie('name', False, max_age=60)
False
4.HttpRequest.is_secure() 如果请求时是安全的,则返回True;即请求通是过 HTTPS 发起的
5.HttpRequest.is_ajax() 如果请求是通过XMLHttpRequest发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django的 cache middleware, 你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
6.HttpRequest.GET.get()、HttpRequest.GET.getlist()、HttpRequest.POST.get()、HttpRequest.POST.getlist() 键值对的值是多个时,比如checkbox类型的input标签,select标签,需要用:request.GET.getlist("bobby")、request.POST.getlist("hobby"),值是单个时则使用get()
上传文件示例
file.html
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="myfile">
<input type="submit">
</form>
views.py
def upload_file(request):
if request.method == 'POST':
file_obj = request.FILES.get('myfile') # file_obj就是文件对象
print(file_obj.name) # 文件名
# 文件操作 将上传的文件写入后端
with open(file_obj.name,'wb') as f:
for line in file_obj: # 或者in file_obj.chunks(),跟file_obj效果一样,file_obj是一个可迭代对象
f.write(line)
return HttpResponse('收到了')
return render(request,'file.html')
Response对象
每个视图都需要实例化,填充和返回一个HttpResponse,HttpResponse类位于django.http模块中。
使用
传递字符串
from django.http import HttpResponse
response = HttpResponse("Here's the text of the Web page.")
response = HttpResponse("Text only, please.", content_type="text/plain")
def index(request):
data = {'name':'jason','password':123}
res = json.dumps(data,ensure_ascii=False)
return HttpResponse(res)
设置或删除响应头信息
response = HttpResponse()
response['Content-Type'] = 'text/html; charset=UTF-8'
del response['Content-Type']
属性
HttpResponse.content:响应内容
HttpResponse.charset:响应内容的编码
HttpResponse.status_code:响应的状态码
HttpResponse对象
django视图函数必须返回一个HttpResponse对象,render、redirect、JsonResponse都继承了HttpResponse
django小白必会三板斧:
HttpResponse: 返回字符串
render: 返回html页面,并且能够给该页面传值
redirect: 302重定向
from django.shortcuts import render,HttpResponse,redirect
def index(request):
return HttpResponse('第一个django')
def login(request):
user_dict = {'name':'jason'}
return render(request,'login.html',{'data':user_dict})
def home(request):
return redirect('/login/') # 302
```![](/i/l/?n=23&i=blog/2932132/202302/2932132-20230213061933798-220663936.png)
**render()**
参数:
request:用于生成响应的请求对象
template_name:要使用的模板的完整名称,可选的参数
context:添加到模板上下文的字典,默认是一个空字典
content_type:生成的文档要使用的MIME类型,默认为 DEFAULT_CONTENT_TYPE 设置的值,默认为'text/html'
status:响应的状态码,默认为200
useing: 用于加载模板的模板引擎的名称
内部原理:
```python
from django.template import Template,Context
def index(request):
temp = Template('<h1>{{ user }}</h1>')
con = Context({"user":{"name":'jason',"password":'123'}})
res = temp.render(con)
return HttpResponse(res)
# 或者
from django.template import loader
def my_view(request):
t = loader.get_template('myapp/index.html')
c = {'foo': 'bar'}
return HttpResponse(t.render(c, request))
redirect()
参数可以是:
-
一个模型:将调用模型的
get_absolute_url()
函数传递一个具体的ORM对象,将调用具体ORM对象的
get_absolute_url()
方法来获取重定向的URL(了解即可):from django.shortcuts import redirect def my_view(request): object = MyModel.objects.get(...) return redirect(object)
-
一个视图:可以带有参数,将使用
urlresolvers.reverse
来反向解析名称def my_view(request): return redirect('some-view-name', foo='bar')
-
一个绝对或相对URL:将原封不动的作为重定向的位置
def my_view(request): return redirect('/some/url/') # 也可以是一个完整的网址:return redirect('http://example.com/')
默认返回一个临时的重定向,传递permanent=True
可以返回一个永久的重定向:
def my_view(request):
return redirect('/some/url/', permanent=True)
扩展阅读:
临时重定向(响应状态码:302)和永久重定向(响应状态码:301)对普通用户来说是没什么区别的,它主要面向的是搜索引擎的机器人。
A页面临时重定向到B页面,那搜索引擎收录的就是A页面。
A页面永久重定向到B页面,那搜索引擎收录的就是B页面。
JsonResponse
JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应
from django.http import JsonResponse
response = JsonResponse({'foo': 'bar'})
print(response.content) # b'{"foo": "bar"}'
def index(request):
data = {'name':'jason','password':123}
l = [1,2,3,4,5,6,7,8]
# return JsonResponse(data,json_dumps_params={'ensure_ascii':False})
return JsonResponse(l,safe=False) # 如果返回的不是字典,需修改safe参数为false
"""
return JsonResponse(data,json_dumps_params={'ensure_ascii':False}) ==>
return HttpResponse(json.dumps(dat,ensure_ascii=False))
"""
django settings源码
"""
前提:
1.django除了暴露给用户一个settings.py配置文件之外,内部还有一个全局的配置文件
from django.conf import global_settings
2.在使用配置文件时,可以直接导入暴露给用户的settings.py,也可以使用django全局的配置文件,并且后者居多
3.django的启动入口是manage.py
"""
# manage.py
if __name__ == "__main__":
#django在启动时,会往全局的大字典os.environ中设置一个键值对,值是暴露给用户的配置文件的路径字符串
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings")
# views.py中写from django.conf import settings,点进settings
settings = LazySettings() # 单例模式
# 点进LazySettings
class LazySettings(LazyObject):
def _setup(self, name=None):
# os.environ可以把它看成是一个全局的大字典
settings_module = os.environ.get(ENVIRONMENT_VARIABLE) # 从大字典中取键为DJANGO_SETTINGS_MODULE所对应的值:day54.settings
# settings_module = 'day54.settings'
self._wrapped = Settings(settings_module) # Settings('day54.settings')
# 点进Settings
class Settings(object):
def __init__(self, settings_module): # settings_module = 'day54.settings'
# update this dict from global settings (but only for ALL_CAPS settings)
for setting in dir(global_settings): # global_settings为django全局配置文件
# dir获取django全局配置文件中所有的变量名
if setting.isupper(): # 判断文件中的变量名是否是大写,大写才生效
setattr(self, setting, getattr(global_settings, setting)) # 给settings对象设置键值对
# settings.文件中大写的变量名 = 文件中大写的变量名所对应的值
# store the settings module in case someone later cares
self.SETTINGS_MODULE = settings_module # 'day54.settings'
mod = importlib.import_module(self.SETTINGS_MODULE) # mod = 模块settings(暴露给用户的配置文件)
for setting in dir(mod): # for循环获取暴露给用户的配置文件中所有的变量名
if setting.isupper(): # 判断变量名是否是大写
setting_value = getattr(mod, setting) # 获取大写的变量名所对应的值
setattr(self, setting, setting_value) # 给settings对象设置键值对
# 利用字典的键存在就是替换的原理,实现了用户配置就用用户配置的否则就用默认的
基于django settings源码实现自定义配置
"""
# 文件层级
- conf
- settings.py
- lib
- conf
__init__.py
global_settings.py
start.py
"""
# settings.py
NAME = '我是暴露给用户的自定义配置'
# __init__.py
import os
import importlib
from lib.conf import global_settings
class Settings(object):
def __init__(self):
# 先for循环获取全局配置文件中所有的变量名
for name in dir(global_settings):
# 判断是否是大写
if name.isupper():
# 给settings对象设置键值对
setattr(self,name,getattr(global_settings,name))
# 从全局大字典中拿到暴露给用户的配置文件的字符串路径
path = os.environ.get('xxx') # path = 'conf.settings'
# 利用importlib模块导入settings模块
module = importlib.import_module(path)
# 再for循环暴露给用户的配置文件中所有的变量名
for name in dir(module):
if name.isupper():
setattr(self,name,getattr(module,name))
settings = Settings()
# global_settings.py
NAME = '我是项目默认的配置'
# start.py
import os
import sys
BASE_DIR = os.path.dirname(__file__)
sys.path.append(BASE_DIR)
if __name__ == '__main__':
# 在项目的全局设置一个大字典
os.environ.setdefault('xxx','conf.settings') # os.environ['xxx'] = 'conf.settings'
from lib.conf import settings
print(settings.NAME) # 当用户在settings.py中配置了就用用户的,否在就用global_settings.py默认的
标签:HttpRequest,03,name,get,settings,request,视图,django
From: https://www.cnblogs.com/jlllog/p/17115167.html