如果你是完美主義者,那麼Django就是你的菜!

2021-03-02 拼客學堂






http請求中產生兩個核心對象:

http請求:HttpRequest對象

http響應:HttpResponse對象

所在位置:django.http

/usr/local/lib/python3.7/site-packages/django/http目錄下的文件:

ElainedeAir:http elaine$ tree.├── __init__.py├── __pycache__│   ├── __init__.cpython-37.pyc│   ├── cookie.cpython-37.pyc│   ├── multipartparser.cpython-37.pyc│   ├── request.cpython-37.pyc│   └── response.cpython-37.pyc├── cookie.py├── multipartparser.py├── request.py└── response.py
1 directory, 10 filesElainedeAir:http elaine$


1. 通過源碼理解HttpResponse對象

在視圖views.py文件中,對於http兩個核心對象的使用方法是:

from django.shortcuts import HttpResponse

django.shortcuts對應具體的文件為:

/usr/local/lib/python3.7/site-packages/django/shortcuts.py

在該文件中有如下內容:

#shortcuts.py文件中內容from django.http import ( Http404, HttpResponse, HttpResponsePermanentRedirect, HttpResponseRedirect,)

上述就是在views.py文件中,對HttpResponse對象的調用邏輯。

HttpResponse對象(源碼)到底在哪個文件中定義?

HttpResponse對象就是下述文件中定義的一個類:

class HttpResponse(HttpResponseBase):    """    An HTTP response class with a string as content.
This content that can be read, appended to, or replaced. """
streaming = False
def __init__(self, content=b'', *args, **kwargs): super().__init__(*args, **kwargs) self.content = content
def __repr__(self): return '<%(cls)s status_code=%(status_code)d%(content_type)s>' % { 'cls': self.__class__.__name__, 'status_code': self.status_code, 'content_type': self._content_type_for_repr, }
def serialize(self): """Full HTTP message, including headers, as a bytestring.""" return self.serialize_headers() + b'\r\n\r\n' + self.content
__bytes__ = serialize
@property def content(self): return b''.join(self._container)
@content.setter def content(self, value): if hasattr(value, '__iter__') and not isinstance(value, (bytes, str)): content = b''.join(self.make_bytes(chunk) for chunk in value) if hasattr(value, 'close'): try: value.close() except Exception: pass else: content = self.make_bytes(value) self._container = [content]
def __iter__(self): return iter(self._container)
def write(self, content): self._container.append(self.make_bytes(content))
def tell(self): return len(self.content)
def getvalue(self): return self.content
def writable(self): return True
def writelines(self, lines): for line in lines:            self.write(line)

從源碼可以看出,HttpResponse是HttpResponseBase的子類:

class HttpResponseBase:    """    An HTTP response base class with dictionary-accessed headers.
This class doesn't handle content. It should not be used directly. Use the HttpResponse and StreamingHttpResponse subclasses instead. """
status_code = 200
def __init__(self, content_type=None, status=None, reason=None, charset=None): # _headers is a mapping of the lowercase name to the original case of # the header (required for working with legacy systems) and the header # value. Both the name of the header and its value are ASCII strings. self._headers = {} self._closable_objects = [] # This parameter is set by the handler. It's necessary to preserve the self._handler_class = None self.cookies = SimpleCookie() self.closed = False if status is not None: try: self.status_code = int(status) except (ValueError, TypeError): raise TypeError('HTTP status code must be an integer.')
if not 100 <= self.status_code <= 599: raise ValueError('HTTP status code must be an integer from 100 to 599.') self._reason_phrase = reason self._charset = charset if content_type is None: content_type = '%s; charset=%s' % (settings.DEFAULT_CONTENT_TYPE, self.charset) self['Content-Type'] = content_type
@property def reason_phrase(self): if self._reason_phrase is not None: return self._reason_phrase return responses.get(self.status_code, 'Unknown Status Code')
@reason_phrase.setter def reason_phrase(self, value): self._reason_phrase = value
@property def charset(self): if self._charset is not None: return self._charset content_type = self.get('Content-Type', '') matched = _charset_from_content_type_re.search(content_type) if matched: return matched.group('charset').replace('"', '') return settings.DEFAULT_CHARSET
@charset.setter def charset(self, value): self._charset = value
def serialize_headers(self): """HTTP headers as a bytestring.""" def to_bytes(val, encoding): return val if isinstance(val, bytes) else val.encode(encoding)
headers = [ (to_bytes(key, 'ascii') + b': ' + to_bytes(value, 'latin-1')) for key, value in self._headers.values() ] return b'\r\n'.join(headers)
__bytes__ = serialize_headers
@property def _content_type_for_repr(self): return ', "%s"' % self['Content-Type'] if 'Content-Type' in self else ''
def _convert_to_charset(self, value, charset, mime_encode=False): """ Convert headers key/value to ascii/latin-1 native strings.
`charset` must be 'ascii' or 'latin-1'. If `mime_encode` is True and `value` can't be represented in the given charset, apply MIME-encoding. """ if not isinstance(value, (bytes, str)): value = str(value) if ((isinstance(value, bytes) and (b'\n' in value or b'\r' in value)) or isinstance(value, str) and ('\n' in value or '\r' in value)): raise BadHeaderError("Header values can't contain newlines (got %r)" % value) try: if isinstance(value, str): value.encode(charset) else: value = value.decode(charset) except UnicodeError as e: if mime_encode: value = Header(value, 'utf-8', maxlinelen=sys.maxsize).encode() else: e.reason += ', HTTP response headers must be in %s format' % charset raise return value
def __setitem__(self, header, value): header = self._convert_to_charset(header, 'ascii') value = self._convert_to_charset(value, 'latin-1', mime_encode=True) self._headers[header.lower()] = (header, value)
def __delitem__(self, header): self._headers.pop(header.lower(), False)
def __getitem__(self, header): return self._headers[header.lower()][1]
def has_header(self, header): """Case-insensitive check for a header.""" return header.lower() in self._headers
__contains__ = has_header
def items(self): return self._headers.values()
def get(self, header, alternate=None): return self._headers.get(header.lower(), (None, alternate))[1]
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False, samesite=None): """ Set a cookie.
``expires`` can be: - a string in the correct format, - a naive ``datetime.datetime`` object in UTC, - an aware ``datetime.datetime`` object in any time zone. If it is a ``datetime.datetime`` object then calculate ``max_age``. """ self.cookies[key] = value if expires is not None: if isinstance(expires, datetime.datetime): if timezone.is_aware(expires): expires = timezone.make_naive(expires, timezone.utc) delta = expires - expires.utcnow() delta = delta + datetime.timedelta(seconds=1) expires = None max_age = max(0, delta.days * 86400 + delta.seconds) else: self.cookies[key]['expires'] = expires else: self.cookies[key]['expires'] = '' if max_age is not None: self.cookies[key]['max-age'] = max_age if not expires: self.cookies[key]['expires'] = http_date(time.time() + max_age) if path is not None: self.cookies[key]['path'] = path if domain is not None: self.cookies[key]['domain'] = domain if secure: self.cookies[key]['secure'] = True if httponly: self.cookies[key]['httponly'] = True if samesite: if samesite.lower() not in ('lax', 'strict'): raise ValueError('samesite must be "lax" or "strict".') self.cookies[key]['samesite'] = samesite
def setdefault(self, key, value): """Set a header unless it has already been set.""" if key not in self: self[key] = value
def set_signed_cookie(self, key, value, salt='', **kwargs): value = signing.get_cookie_signer(salt=key + salt).sign(value) return self.set_cookie(key, value, **kwargs)
def delete_cookie(self, key, path='/', domain=None): secure = key.startswith(('__Secure-', '__Host-')) self.set_cookie( key, max_age=0, path=path, domain=domain, secure=secure, expires='Thu, 01 Jan 1970 00:00:00 GMT', )

def make_bytes(self, value): """Turn a value into a bytestring encoded in the output charset."""
if isinstance(value, bytes): return bytes(value) if isinstance(value, str): return bytes(value.encode(self.charset)) return str(value).encode(self.charset)

def close(self): for closable in self._closable_objects: try: closable.close() except Exception: pass self.closed = True signals.request_finished.send(sender=self._handler_class)
def write(self, content): raise IOError("This %s instance is not writable" % self.__class__.__name__)
def flush(self): pass
def tell(self): raise IOError("This %s instance cannot tell its position" % self.__class__.__name__)

def readable(self): return False
def seekable(self): return False
def writable(self): return False
def writelines(self, lines): raise IOError("This %s instance is not writable" % self.__class__.__name__)

2. 通過源碼理解HttpRequest對象

django.http是框架最核心的部分,框架把客戶端的url請求轉換成HttpRequest, 傳遞給我們自己寫的view函數,在上面的代碼裡就是index。由view函數負責生成HttpResponse對象返回給框架, 框架根據這個對象做相應的處理,返回給客戶端。

class HttpRequest:    def __init__(self):        ...
def __repr__(self): ... @cached_property def headers(self): ...
def _get_raw_host(self): ...
def get_host(self): ... def get_port(self): ...
def get_full_path(self, force_append_slash=False): ...
def get_full_path_info(self, force_append_slash=False): ...
def _get_full_path(self, path, force_append_slash): ...
def get_signed_cookie(self, key, default=RAISE_ERROR, salt='', max_age=None): ...
def get_raw_uri(self): ...
def build_absolute_uri(self, location=None): ...
@cached_property def _current_scheme_host(self): ... def _get_scheme(self): ...
@property def scheme(self): ...
def is_secure(self): ...
def is_ajax(self): ... @property def encoding(self): return self._encoding
@encoding.setter def encoding(self, val): ...
def _initialize_handlers(self): ... @property def upload_handlers(self): ...
@upload_handlers.setter def upload_handlers(self, upload_handlers): ...
def parse_file_upload(self, META, post_data): ...
@property def body(self): ...
def _mark_post_parse_error(self): ... def _load_post_and_files(self): ... def close(self): ...
def read(self, *args, **kwargs): ... def readline(self, *args, **kwargs): ...
def __iter__(self): ...
def xreadlines(self): ...
def readlines(self): ...


3. HttpRequest類對象方法介紹

HttpRequest類中有幾個比較重要的方法:

3.1Django配置說明

from blog import viewsfrom django.conf.urls import url,includeurlpatterns = [    url(r'login',views.login,name='bieming'),    ]


def login(request): if request.method=='POST': username=request.POST.get('username') password=request.POST.get('password') if username=='laowang' and password=='pinginglab': return HttpResponse("登陸成功") return render(request,'login')


<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body><form action="{% url 'bieming' %}" method="POST">         用戶名:<input type="text" name="username">         密碼:<input type="password" name="password">         <input type="submit" value="submit">     </form></body></html>

3.2 方法介紹

3.2.1 request.scheme

A string representing the scheme of the request (httporhttpsusually).

3.2.2 request.body

The raw HTTP request body as a byte string. This is useful for processing data in different ways than conventional HTML forms: binary images, XML payload etc. For processing conventional form data, useHttpRequest.POST.

You can also read from an HttpRequest using a file-like interface. SeeHttpRequest.read().

演示配置中,如果在視圖函數中增加一行:

輸出結果為:

b'' b'username=laowang&password=pinginglab' 

3.2.3 request.path

A string representing the full path to the requested page,not including the scheme or domain.

Example:"/music/bands/the_beatles/"

3.2.4 request.path_info

Under some Web server configurations, the portion of the URL after the host name is split up into a script prefix portion and a path info portion. Thepath_infoattribute always contains the path info portion of the path, no matter what Web server is being used. Using this instead ofpathcan make your code easier to move between test and deployment servers.

For example, if theWSGIScriptAliasfor your application is set to"/minfo", thenpathmight be"/minfo/music/bands/the_beatles/"andpath_infowould be"/music/bands/the_beatles/".

在某些Web伺服器配置下,主機名後的URL部分被分成腳本前綴部分和路徑信息部分。path_info屬性將始終包含路徑信息部分,不論使用的Web伺服器是什麼。使用它代替path可以讓代碼在測試和開發環境中更容易地切換。

例如,如果應用的WSGIScriptAlias設置為/minfo,那麼HttpRequest.path等於/music/bands/the_beatles/,而HttpRequest.path_info為/minfo/music/bands/the_beatles/


3.2.5 request.method

A string representing the HTTP method used in the request. This is guaranteed to be uppercase. Example:

if request.method == 'GET': do_something()elif request.method == 'POST': do_something_else()

通過這個屬性來判斷請求的方法,然後根據請求的方法不同,在視圖中執行不同的代碼。


3.2.6 request.encoding

A string representing the current encoding used to decode form submission data (orNone, which means theDEFAULT_CHARSETsetting is used). You can write to this attribute to change the encoding used when accessing the form data. Any subsequent attribute accesses (such as reading fromGETorPOST) will use the newencodingvalue. Useful if you know the form data is not in theDEFAULT_CHARSETencoding.

字符串類型,表示提交的數據的編碼方式(如果為None 則表示使用DEFAULT_CHARSET設置)。 這個屬性是可寫的,可以通過修改它來改變表單數據的編碼。任何隨後的屬性訪問(例如GET或POST)將使用新的編碼方式。


3.2.7 request.content_type

A string representing the MIME type of the request, parsed from theCONTENT_TYPEheader.

Django1.10中新增。表示從CONTENT_TYPE頭解析的請求的MIME類型

3.2.8 request.content_params

A dictionary of key/value parameters included in theCONTENT_TYPEheader.


3.2.9 request.GET

A dictionary-like object containing all given HTTP GET parameters. See theQueryDictdocumentation below.


3.2.10 request.POST

A dictionary-like object containing all given HTTP POST parameters, providing that the request contains form data. See theQueryDictdocumentation below. If you need to access raw or non-form data posted in the request, access this through theHttpRequest.bodyattribute instead.

It’s possible that a request can come in via POST with an emptyPOSTdictionary – if, say, a form is requested via the POST HTTP method but does not include form data. Therefore, you shouldn’t useif request.POSTto check for use of the POST method; instead, useifrequest.method == "POST"(seeHttpRequest.method).

POSTdoesnotinclude file-upload information. SeeFILES.


3.2.11 request.COOKIES

A dictionary containing all cookies. Keys and values are strings.

3.2.12 request.FILES

A dictionary-like object containing all uploaded files. Each key inFILESis thenamefrom the<input type="file" name="">. Each value inFILESis anUploadedFile.

SeeManaging filesfor more information.

FILESwill only contain data if the request method was POST and the<form>that posted to the request hadenctype="multipart/form-data". Otherwise,FILESwill be a blank dictionary-like object.


3.2.13 request.META

A dictionary containing all available HTTP headers. Available headers depend on the client and server, but here are some examples:

CONTENT_LENGTH– The length of the request body (as a string).

CONTENT_TYPE– The MIME type of the request body.

HTTP_ACCEPT– Acceptable content types for the response.

HTTP_ACCEPT_ENCODING– Acceptable encodings for the response.

HTTP_ACCEPT_LANGUAGE– Acceptable languages for the response.

HTTP_HOST– The HTTP Host header sent by the client.

HTTP_REFERER– The referring page, if any.

HTTP_USER_AGENT– The client’s user-agent string.

QUERY_STRING– The query string, as a single (unparsed) string.

REMOTE_ADDR– The IP address of the client.

REMOTE_HOST– The hostname of the client.

REMOTE_USER– The user authenticated by the Web server, if any.

REQUEST_METHOD– A string such as"GET"or"POST".

SERVER_NAME– The hostname of the server.

SERVER_PORT– The port of the server (as a string).


With the exception of CONTENT_LENGTH and CONTENT_TYPE, as given above, any HTTP headers in the request are converted toMETAkeys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP_ prefix to the name. So, for example, a header called X-Bender would be mapped to the META key HTTP_X_BENDER.

Note thatrunserverstrips all headers with underscores in the name, so you won’t see them in META. This prevents header-spoofing based on ambiguity between underscores and dashes both being normalizing to underscores in WSGI environment variables. It matches the behavior of Web servers like Nginx and Apache 2.4+.


3.2.14 request.resolver_match

An instance ofResolverMatchrepresenting the resolved URL. This attribute is only set after URL resolving took place, which means it’s available in all views but not in middleware which are executed before URL resolving takes place (you can use it inprocess_view()though).


3.2.15 request.session

From theSessionMiddleware: A readable and writable, dictionary-like object that represents the current session.

3.2.16 request.user

From theAuthenticationMiddleware: An instance ofAUTH_USER_MODELrepresenting the currently logged-in user. If the user isn’t currently logged in,userwill be set to an instance ofAnonymousUser. You can tell them apart withis_authenticated, like so:

if request.user.is_authenticated: ... # Do something for logged-in users.else: ... # Do something for anonymous users.

AuthenticationMiddleware中間件:表示當前登錄的用戶的AUTH_USER_MODEL的實例,這個模型是Django內置的Auth模塊下的User模型。如果用戶當前未登錄,則user將被設置為AnonymousUser的實例。


3.2.17 request..get_host()

Returns the originating host of the request using information from theHTTP_X_FORWARDED_HOST(ifUSE_X_FORWARDED_HOSTis enabled) andHTTP_HOSTheaders, in that order. If they don’t provide a value, the method uses a combination ofSERVER_NAMEandSERVER_PORTas detailed inPEP 3333.

Example:"127.0.0.1:8000"

Note:

Theget_host()method fails when the host is behind multiple proxies. One solution is to use middleware to rewrite the proxy headers, as in the following example:

from django.utils.deprecation import MiddlewareMixin
class MultipleProxyMiddleware(MiddlewareMixin): FORWARDED_FOR_FIELDS = [ 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED_HOST', 'HTTP_X_FORWARDED_SERVER', ]
def process_request(self, request): """ Rewrites the proxy headers so that only the most recent proxy is used. """ for field in self.FORWARDED_FOR_FIELDS: if field in request.META: if ',' in request.META[field]: parts = request.META[field].split(',') request.META[field] = parts[-1].strip()

This middleware should be positioned before any other middleware that relies on the value ofget_host()– for instance,CommonMiddlewareorCsrfViewMiddleware.


3.2.18 request.get_port()

Returns the originating port of the request using information from theHTTP_X_FORWARDED_PORT(ifUSE_X_FORWARDED_PORTis enabled) andSERVER_PORTMETAvariables, in that order.


3.2.19 request.get_full_path()與get_full_path_info()

Returns thepath, plus an appended query string, if applicable.

Example:"/music/bands/the_beatles/?print=true"

request.get_full_path_info():

New in Django 2.1

Likeget_full_path(), but usespath_infoinstead ofpath.

Example:"/minfo/music/bands/the_beatles/?print=true"


3.2.20 request.build_absolute_uri(location)

Returns the absolute URI form oflocation. If no location is provided, the location will be set torequest.get_full_path().

If the location is already an absolute URI, it will not be altered. Otherwise the absolute URI is built using the server variables available in this request. For example:

>>> request.build_absolute_uri()'https://example.com/music/bands/the_beatles/?print=true'>>> request.build_absolute_uri('/bands/')'https://example.com/bands/'>>> request.build_absolute_uri('https://example2.com/bands/')'https://example2.com/bands/'

Note:

Mixing HTTP and HTTPS on the same site is discouraged, thereforebuild_absolute_uri()will always generate an absolute URI with the same scheme the current request has. If you need to redirect users to HTTPS, it’s best to let your Web server redirect all HTTP traffic to HTTPS.


3.2.21 request.get_signed_cookie(key,default=RAISE_ERROR,salt='',max_age=None)

Returns a cookie value for a signed cookie, or raises adjango.core.signing.BadSignatureexception if the signature is no longer valid. If you provide thedefaultargument the exception will be suppressed and that default value will be returned instead.

The optionalsaltargument can be used to provide extra protection against brute force attacks on your secret key. If supplied, themax_ageargument will be checked against the signed timestamp attached to the cookie value to ensure the cookie is not older thanmax_ageseconds.

For example:

>>> request.get_signed_cookie('name')'Tony'>>> request.get_signed_cookie('name', salt='name-salt')'Tony' >>> request.get_signed_cookie('nonexistent-cookie')...KeyError: 'nonexistent-cookie'>>> request.get_signed_cookie('nonexistent-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

3.2.22 request.is_secure()

ReturnsTrueif the request is secure; that is, if it was made with HTTPS.


3.2.23 request.is_ajax()

ReturnsTrueif the request was made via anXMLHttpRequest, by checking theHTTP_X_REQUESTED_WITHheader for the string'XMLHttpRequest'. Most modern JavaScript libraries send this header. If you write your ownXMLHttpRequestcall (on the browser side), you』ll have to set this header manually if you wantis_ajax()to work.

If a response varies on whether or not it’s requested via AJAX and you are using some form of caching like Django’scachemiddleware, you should decorate the view withvary_on_headers('X-Requested-With')so that the responses are properly cached.


3.2.24 request.read(size=None)3.2.25 request.readline()3.2.26 request.readlines()3.2.27 request.xreadlines()3.2.28 request.__iter__()

Methods implementing a file-like interface for reading from anHttpRequestinstance. This makes it possible to consume an incoming request in a streaming fashion. A common use-case would be to process a big XML payload with an iterative parser without constructing a whole XML tree in memory.

Given this standard interface, anHttpRequestinstance can be passed directly to an XML parser such asElementTree:

import xml.etree.ElementTree as ETfor element in ET.iterparse(request): process(element)

3.3 幾個重要屬性與方法介紹

3.3.1request.headers

修改視圖函數:

def login(request):    print (request.headers) 

查看視圖函數輸出結果:

{'Content-Length': '', 'Content-Type': 'text/plain', 'Host': '127.0.0.1:8080', 'Connection': 'keep-alive', 'Cache-Control': 'max-age=0', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Cookie': 'SL_G_WPT_TO=zh; SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; csrftoken=h0euPNihCLct0kaBefG0oj1aFwAXW4FlFwfOyKhSOSofGUE79OnaW8h5Rx6eVMSh; sessionid=2fq4v9sukcg1i5emuooc2ahteeehve6b'}


3.3.2request.path

修改視圖函數:

查看視圖函數輸出結果:

3.3.3request.method

修改視圖函數:

查看視圖函數輸出結果:

3.3.4request.POST

修改視圖函數:

查看視圖函數輸出結果:

<QueryDict: {}>
<QueryDict: {'username': ['pinginglab'], 'password': ['pinginglab']}>

3.3.5request.GET

修改視圖函數:

查看視圖函數輸出結果:


3.3.6request.COOKIES

修改視圖函數:

查看視圖函數輸出結果:

{'SL_G_WPT_TO': 'zh', 'SL_GWPT_Show_Hide_tmp': '1', 'SL_wptGlobTipTmp': '1', 'csrftoken': 'h0euPNihCLct0kaBefG0oj1aFwAXW4FlFwfOyKhSOSofGUE79OnaW8h5Rx6eVMSh', 'sessionid': '2fq4v9sukcg1i5emuooc2ahteeehve6b'}

包含所有cookies的標準Python字典對象;

keys和values都是字符串

3.3.7request.FILES

修改視圖函數:

查看視圖函數輸出結果:

包含所有上傳文件的類字典對象;

FILES中的每一個Key都是<input type="file" name="" />標籤中name屬性的值,FILES中的每一個value同時也是一個標準的python字典對象,包含下面三個Keys:

filename: 上傳文件名,用字符串表示content_type: 上傳文件的Content Typecontent: 上傳文件的原始內容


3.3.8request.user

修改視圖函數:

查看視圖函數輸出結果:

注意:

這個是獲取我們創建的django的後臺管理員帳號,與login文件中的form表單中的username沒有任何關係。

是一個django.contrib.auth.models.User對象,代表當前登陸的用戶。如果訪問用戶當前沒有登陸,user將被初始化為django.contrib.auth.models.AnonymousUser的實例。你可以通過user的is_authenticated()方法來辨別用戶是否登陸:

if req.user.is_authenticated()

只有激活Django中的AuthenticationMiddleware時該屬性才可用。

3.3.9Request.session

修改視圖函數:

查看視圖函數輸出結果:

<django.contrib.sessions.backends.db.SessionStore object at 0x104a42780>

這個是由中間件設置的屬性:

MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',]

SessionMiddleware中間件:一個可讀寫的,類似字典的對象,表示當前會話。

我們要保存用戶狀態,會話過程等等,靠的就是這個中間件和這個屬性。

3.3.10request.get_full_path()

修改視圖函數:

print (request.get_full_path())

查看視圖函數輸出結果:

/login/index.html?name=pinginglab

比如:http://127.0.0.1:8080/login/index.html?name=pinginglab

request.get_full_path()得到的結果就是/login/index.html?name=pinginglab

Request.path得到的結果就是/login/index.html


3.3.11request.POST.getlist('')

django中通過getlist()接收頁面form的post數組。

Recently I tried sending a list through a form using something like<input name="mylist[]" value="some val">*.  When this form is submitted all of the inputs with that name are grouped together for easy access.  In Django, one would think you could simply access the list usingrequest.POST['mylist[]']

.  This is not the case.Using that command will give you the last value.  Django says this is a featureand to get the list userequest.POST.getlist('my_list[]').


4. redirect()與locals()函數

/usr/local/lib/python3.7/site-packages/django/shortcuts.py文件中定義了一個函數redirect();

Python本身有一個內置函數locals();

4.1 深入理解redirect()函數

4.1.1 產生的背景

舉個例子:當用戶在頁面上註冊好後,希望能夠直接自動將登錄頁面加載給用戶。這個時候就涉及到跳轉的問題。用戶註冊執行的是視圖函數中的register函數,用戶登錄執行的是login函數,在register函數中做判斷,當用戶註冊成功後,可以直接調用登錄相關的視圖函數。

redirect()函數源碼:

def redirect(to, *args, permanent=False, **kwargs): """ Return an HttpResponseRedirect to the appropriate URL for the arguments passed.
The arguments could be:
* A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urls.reverse()` will be used to reverse-resolve the name.
* A URL, which will be used as-is for the redirect location.
Issues a temporary redirect by default; pass permanent=True to issue a permanent redirect. """ redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect return redirect_class(resolve_url(to, *args, **kwargs))

4.1.2 案例演示

from blog import viewsfrom django.conf.urls import url,includeurlpatterns = [ path('admin/', admin.site.urls), path('show_time/', views.show_time), url(r'^blog/',include('blog.urls')), url(r'^register$',views.register,name='register'), url(r'login',views.login,name='bieming'), ]

def register(request): if request.method=='POST': username=request.POST.get('username') password=request.POST.get('password') if username and password: return redirect('/login/') #注意一定要帶上"/",不能直接只寫"login" return render(request,'register')
def login(request): if request.method=='POST': username=request.POST.get('username') password=request.POST.get('password') if username=='laowang' and password=='pinginglab': return HttpResponse("登陸成功") return render(request,'login')

#register<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>用戶註冊</title></head><body><form action="{% url 'register' %}" method="POST"> 用戶名:<input type="text" name="username"> 密碼:<input type="password" name="password"> <input type="submit" value="submit"> </form></body></html>

#login<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>用戶登錄</title></head><body><form action="{% url 'login' %}" method="POST"> 用戶名:<input type="text" name="username"> 密碼:<input type="password" name="password"> <input type="submit" value="submit"> </form></body></html>

註冊到登錄的跳轉

註冊界面

填寫用戶名與密碼後,點擊提交


點擊提交後,直接跳轉到登錄界面


輸入帳號密碼進行登錄

4.2 深入理解locals()函數

4.2.1 背景理解

render與render_to_response函數:

def render_to_response(template_name, context=None, content_type=None, status=None, using=None): """ Return a HttpResponse whose content is filled with the result of calling django.template.loader.render_to_string() with the passed arguments. """ warnings.warn( 'render_to_response() is deprecated in favor of render(). It has the ' 'same signature except that it also requires a request.', RemovedInDjango30Warning, stacklevel=2, ) content = loader.render_to_string(template_name, context, using=using) return HttpResponse(content, content_type, status)def render(request, template_name, context=None, content_type=None, status=None, using=None): """ Return a HttpResponse whose content is filled with the result of calling django.template.loader.render_to_string() with the passed arguments. """ content = loader.render_to_string(template_name, context, request, using=using) return HttpResponse(content, content_type, status)

簡單演示render函數的使用:

from django.contrib import adminfrom django.urls import pathfrom blog import viewsfrom django.conf.urls import url,includeurlpatterns = [ path('show_time/', views.show_time), ]

def show_time(request): t = time.ctime() return render(request,"index",{"time":t})

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <Title>Title</Title> <style> * { margin:0; padding:0 }</style></head><body> <h1>hello,{{ time }}</h1></body></html>

梳理演示render函數中顯示的結果:

4.2.2 案例演示

通過演示render函數的使用,細心的童鞋會發現一個問題:如果視圖函數中定義了很多個變量時,就需要在視圖函數中調用render函數時,都寫到字典中,導致開發效率低下。怎麼解決這個問題呢?

def show_time(request):    t = time.ctime()    return render(request,"index",{"time":t})     

在該視圖函數中,視圖函數將結果保存到t這個變量中,然後將變量發送給模板,喜歡偷懶的程式設計師應該注意到了,不斷地為臨時變量和臨時模板命名有那麼一點點多餘。 不僅多餘,而且需要額外的輸入。

如果你是個喜歡偷懶的程式設計師並想讓代碼看起來更加簡明,可以利用Python的內建函數locals()。它返回的字典對所有局部變量的名稱與值進行映射。

修改視圖函數為:

def show_time(request):    t = time.ctime()    current_date = datetime.datetime.now()    return render(request,"index",locals())

修改index這個html文件為:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <Title>Title</Title>    <style>        * {            margin:0;            padding:0        }</style></head><body>    <h1>hello,{{ t }}</h1> #注意這一行,從{{ time }}變成了{{ t }}</body>
</html>


{{ time }}是因為之前在視圖函數中使用了{"time":t}。

在此,我們沒有像之前那樣手工指定context字典,而是傳入了locals()的值,它囊括了函數執行到該時間點時所定義的一切變量。使用locals()時要注意是它將包括 所有 的局部變量,它們可能比你想讓模板訪問的要多。

——END——

相關焦點

  • 12星座:你的他是完美主義者嗎?
    開創星座:牡羊、巨蟹、天秤、魔羯如果想分辨開創星座的他是不是一個完美主義者,你可以從他的日常習慣去發現,他是否會「自律」是你觀察的重點,若他在生活中顯現出整齊、簡約、或者軍事化的性格。例如: 他會要求一個口令一個動作,或他家的東西都是經過他精挑細選,足以令他自豪的才擺設出來、或他東西雖然不多,但你看得到的都是精品。會這樣對自己要求自律、對生活要求品質與風格的開創星座情人,他就可能是完美主義者。
  • 完美主義者的內心世界
    你是幾分的"完美主義者"?先來個小測試吧!共有10題,如果你覺得以下描述符合你自己的特點,就得1分,不符合就得0分。來吧,準備好了沒有?1.肯努力改正自己的缺點。但是,就是因為他太好啦,所以他看誰誰不順眼,看誰誰都是一灘爛泥。完美主義者人生處處要求完美。這個世界離完美太遠,所以他對這個世界充滿了不解,挑剔和憤怒。他經常噴火。
  • 完美主義者的10條標準
    佐證之一是:近些年的研究發現,完美主義者和自殺之間存在相當危險的相關性。尤其是,完美主義和抑鬱症的組合,簡直就是一把上了膛的槍。因為,完美主義者們不會衝動做事,他們謹慎行事,善於計劃。一旦一個完美主義者決心自殺,他的特質也會讓自殺任務更容易成功。
  • 承認不完美,是完美主義者的終極解藥.
    他們,不過是沒有他們所設想的那麼好罷了。「可是,你成績好呀!上學期考試,你不還考了全班第一嗎?」 我向來訪者指出。「那有什麼用?」來訪者迅速回擊了我。「你個高腿長,是馬拉松健將,還是漂亮的馬甲線。」我繼續提醒她。
  • 九型人格心理學:完美主義者的人際關係是什麼樣的?
    完美主義者企求完美的關係,當缺點如他們所願、不可避免地出現時,他們會去看看自己是否哪裡做錯。如果沒有,他們很容易憎恨並責備他們的伴侶。「控制是必要的,這樣我才能確保一切會完美呈現。我發現設定清楚的基本原則很重要,就算不夠明確,那也是規則的一部分。
  • 林大廚餐後在廚房刷碗,黃曉明:你是完美主義者,我也是!
    一個正常的餐廳應該是分工清楚的,比如大廚負責炒菜,有專門的刷碗工,配菜工,清潔工等等,可你見過一個國宴級廚師在炒了幾個小時的菜以後還要刷碗的嗎?這不,在最新一期《中餐廳》節目中,這一幕就出現了,站著一旁的黃曉明說的這句話引發了網友熱議!
  • 緋夜心理小課堂——從九型人格的角度分析完美主義者
    完美主義者不開心的原因是什麼?書中是這樣解讀完美主義者的:人類被上帝創造出來時是完美無瑕的狀態,而嬰兒初來到人間時也是完美無瑕的。這個時候不會去區分「你我」、「好壞」,一切都是一體的。每個人都是先天完美。隨著成長,有意思的事情發生了。你會發現自己沒辦法像想像中做的那麼好,總是有些事不盡如人意,而自己也會有種種缺點,比如懶惰,比如粗心大意。不管做什麼,好像都不完美。
  • 你也是不勤奮的完美主義者嗎?
    其實就是俗話常說的,關我屁事 & 關你屁事。嗯,多說 Nevermind 有益身心健康。——自己就是一個完美主義者,啥事都想幹好,結果精疲力盡啥事也沒幹好, i am not a perfect boy~!在上周的晚餐聚會上,我和一個朋友探討了關於平衡自我這個複雜的問題。
  • 一個完整的Django入門指南
    使用諸如 Django 之類的網絡框架,使我們能夠以標準化的方式快速開發安全可靠的Web應用程式,而無需重新發明輪子。那麼,Django有什麼特別之處呢?對於初學者來說,它是一個Python Web框架,這意味著你可以受益於各種各樣的開源庫包。python軟體包資料庫(pypi)擁有超過11.6萬個軟體包(2017年9月6日的數據)。
  • 完美主義的五個星座:可能你自己都沒發現你就是
    你是否會花更多的時間去做一件事來確保每一個細節都是完美的呢?也許你是個徹頭徹尾的控制狂,除非你知道你是完全負責的,否則你是不會放手的。如果你是這樣的人,你可能是一個完美主義者。但也許你根本就不認為自己是個完美主義者。
  • 一篇文章帶你了解Django ORM操作(高端篇)
    感興趣的小夥伴可以戳這兩篇文章學習下,一篇文章帶你了解Django ORM操作(進階篇)、一篇文章帶你了解Django ORM操作(基礎篇)。但是還是遺留了一些技能。,再來瞅瞅吧!如果分組分的不是外鍵欄位,那就不能再跟values!
  • 「完美主義者」的內心
    完美主義者顧名思義就是凡事都要完美。做一件事情力求完美,做一個手工品力求完美,畫一幅畫力求完美,做人也會想著力求完美。weilan從事情上來看,無疑就是什麼都想做到最好,不想把不完美的東西給別人看,所以就會強迫自己什麼都要做好,做不好繼續做,直到自己滿意為止,雖然是自以為的可以,但是內心都會覺得已經很不錯了
  • 成為適應不良的完美主義者意味著什麼?
    根據新研究發表在《心理學前沿》上的答案可能取決於您是完美主義者的類型。來自挪威卑爾根大學的一組研究人員提供了令人信服的證據,證明實際上有兩種類型的 完美主義者一種名為「努力」的完美主義者,可能與積極的心理結果相關,另一種稱為「評估」的完美主義者,可能與心理問題相關。研究人員指出:「儘管目前尚無關於完美主義的指導性定義,但通常將其定義為由不切實際的高期望和過於嚴格的自我評估組成。」 「隨著大量湧入的研究發現了完美主義的負面影響和相關性,關於完美主義是否可以適應的爭論越來越多。」
  • 看看你是個極度完美主義者嗎?你中招了嗎
    極度完美主義心理測試!極端心理情感調查!你中招了嗎?大家好,我是華恩!上一篇的內容我們分析了性格心理的一種,就是完美型性格特質的這類人,這種性格具有很多的內在優勢和外在品質,值得我們去參考和學習。那麼我們再來分析分析一種較為極端的個性情感感受,那就是&34;。讓我們來看一看,這類人在生活中的情緒表現,以及他們的情感感受是如何的。那麼挑戰開始了!你敢來做這個情感測試調查嗎?看看你是不是一名&34;!
  • 10道題教你使用python Django框架來實現web應用,值得收藏
    關於django升級:django1.5開始支持python3。同時django1.11是支持python2的最後的版本。如果使用的django版本大於等於1.5,則django版本可以不升級。如果django版本低於1.5,則需要升級django版本。升級django版本後,新版本不兼容的老的API都需要修改。這個工作量比較大。
  • 《黑天鵝》:不要做職場中的完美主義者,完成比完美更重要
    不過,今天我們換個角度來看《黑天鵝》,從職場層面來聊一個有趣的話題:【不要做職場中的完美主義者,完成比完美更重要】。01、職場中的完美主義真的完美嗎?《黑天鵝》中,尼娜就是一個完美主義者。你,是完美主義者嗎?
  • Django&DataTables應用
    import HttpResponsefrom django.core import serializersfrom .models import MyModel def myModel_asJson(request):    object_list = MyModel.objects.all()     json
  • 抑鬱:病態的完美主義者,大多會迷失自我
    我們都知道,病態的完美主義者,總覺得自己應該是理想中的那個完美的自己,而不應該是現實中那個失敗的不堪的自己。有一個很有趣的現象,很多病態的完美主義者,不喜歡照鏡子,原因其實也很簡單,就是因為鏡子中自己真實的長相,和他們想像中相差太大,他們不忍去直視。很多時候,他們看著鏡子中的自己會突然感覺很陌生,他們很難相信,這真的是我嗎?我怎麼可以長成這個樣子?病態完美主義者不敢面對現實這個特點,從這件小事中就能夠看的很清楚。
  • django-admin和manage.py用法
    金句:所有的天賦,都來自於你對你喜歡的某種事物的模仿與學習,否則你就不會有這種天賦。開篇話:我們在Django開發過程中,命令行執行最多的應該就是python manage.py <command>,今天聊聊manage.py這個命令。
  • python程式設計師嘔心瀝血整理 Django 優秀資源大全
    該應用提供的 Tag 和 Filter 能讓你快速將表單呈現成 div 格式,同時又提供大量的功能來配置和控制呈現的 HTML。django-floppyforms, star:681 - django-floppyforms 這個應用能讓你完全控制表單的呈現結果。