首页 > 其他分享 >03 视图层

03 视图层

时间:2023-02-13 06:33:05浏览次数:42  
标签:HttpRequest 03 name get settings request 视图 django

视图层

一个视图函数(类),简称视图,是一个简单的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

相关文章

  • https//mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/linux-64'
    CondaHTTPError:HTTP000CONNECTIONFAILEDforurl<https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/linux-64/current_repodata.json> Elap......
  • day07-SpringMVC底层机制简单实现-03
    SpringMVC底层机制简单实现-03https://github.com/liyuelian/springmvc-demo.git7.任务6-完成控制器方法获取参数-@RequestParam功能说明:自定义@RequestParam注解和......
  • Oops, It's Yesterday Once Twice Three times.
    严谨一点讲,这叫广义串并联图方法,即:删一度点,缩二度点,叠合重边。通俗一点讲,叫:把看上去显然的情况做掉答案就出来了[USACO22OPEN]HoofandBrainP按照套路,先考虑没有出边......
  • 003:C++继承
    1:C++多继承 1:基类和派生类   面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样......
  • CF1528D It's a bird! No, it's a plane! No, it's AaParsa!
    个人思路:floyd求最短路,\(\Theta(n^3)\)不能维护边的变化。然后就不会做了。正解:首先,对于每个起始点,到达一个点\(v\)越早越好,因为可以等待。边的变化相当于每个节......
  • sqlalchemy+pandas:错误 'OptionEngine' object has no attribute 'execute','str&
    场景:使用 sqlalchemy+pandas1.  'OptionEngine'objecthasnoattribute'execute'importpandasaspdfromsqlalchemyimportcreate_engine,textengine=c......
  • 视图层总结
    目录视图层总结一、两个视图基类二、五个视图扩展类三、九个视图子类四、视图集五、总结视图层总结一、两个视图基类fromrest_framework.viewsimportAPIViewfromr......
  • 学习打卡03-流程控制
    前言:程序中最经典的三种执行顺序顺序结构:自上而下的执行代码分支结构:根据条件,选择对应的代码执行ifswitch循环结构:控制某段代码重复执行......
  • rror: error:0308010C:digital envelope routines::unsupported
    node版本太高  添加两句话参考文档:(101条消息)Error:error:0308010C:digitalenveloperoutines::unsupported错误解决_特级忍者猪的博客-CSDN博客......
  • 基于九个视图子类写五个接口
    目录基于九个视图子类写五个接口一、准备工作把模型表、序列化类、路由代码贴上去吧二、通过九个视图写接口基于九个视图子类写五个接口​ 编写代码的过程中代码的可用性......