DjangoTemplates backend in the TEMPLATES settingTemplates | Django documentation | Django
DjangoTemplates backend in the TEMPLATES setting,就1個 DjangoTemplates backend in the TEMPLATES setting其中的參數:context_processors
:
a list of dotted Python paths to callables that are used to populate the context when a template is rendered with a request. These callables take a request object as their argument and return adict
of items to be merged into the context.
於是這個引擎就具有抽取request信息的能力了。
Templates | Django documentation | Django ?
docs.djangoproject.com
Template實例化時,如果沒有傳入engine,會指定為默認的。engine = Engine.get_default()
[docs]class Template:
def __init__(self, template_string, origin=None, name=None, engine=None):
# If Template is instantiated directly rather than from an Engine and
# exactly one Django template engine is configured, use that engine.
# This is required to preserve backwards-compatibility for direct use
# e.g. Template(...).render(Context({...}))
if engine is None:
from .engine import Engine
engine = Engine.get_default()
if origin is None:
origin = Origin(UNKNOWN_SOURCE)
self.name = name
self.origin = origin
self.engine = engine
self.source = str(template_string) # May be lazy.
self.nodelist = self.compile_nodelist()
然後看看默認的引擎什麼樣……the underlyingEnginefrom the first configured DjangoTemplatesengine,就是第一個配置的引擎。
def get_default():
"""
Return the first DjangoTemplates backend thats configured, or raise
ImproperlyConfigured if none are configured.
This is required for preserving historical APIs that rely on a
globally available, implicitly configured engine such as:
>>> from django.template import Context, Template
>>> template = Template("Hello {{ name }}!")
>>> context = Context({name: "world"})
>>> template.render(context)
Hello world!
"""
# Since Engine is imported in django.template and since
# DjangoTemplates is a wrapper around this Engine class,
# local imports are required to avoid import loops.
from django.template import engines
from django.template.backends.django import DjangoTemplates
for engine in engines.all():
if isinstance(engine, DjangoTemplates):
return engine.engine
raise ImproperlyConfigured(No DjangoTemplates backend is configured.)
The Django template language: for Python programmers ?
docs.djangoproject.com
2、The django.template.loader
module provides functions such as get_template()
for loading templates. They return a django.template.backends.django.Template
which wraps the actual django.template.Template
.
render調用了render_to_string,render_to_string就是在loading template產生template——這是一個template.backends.django.Template類型,包裝了真正的django.template.Template
template.backends.django.Template具有render方法,到了第3步就可以直接調用。
[docs]def render_to_string(template_name, context=None, request=None, using=None):
"""
Load a template and render it with a context. Return a string.
template_name may be a string or a list of strings.
"""
if isinstance(template_name, (list, tuple)):
template = select_template(template_name, using=using)
else:
template = get_template(template_name, using=using)
return template.render(context, request)
其中get_template就是先找到引擎,然後調用引擎的engine.get_template(template_name)。得到的template就帶有引擎的信息。
[docs]def get_template(template_name, using=None):
"""
Load and return a template for the given name.
Raise TemplateDoesNotExist if no such template exists.
"""
chain = []
engines = _engine_list(using)
for engine in engines:
try:
return engine.get_template(template_name)
except TemplateDoesNotExist as e:
chain.append(e)
raise TemplateDoesNotExist(template_name, chain=chain)
其中,_engine_list返回
def _engine_list(using=None):
return engines.all() if using is None else [engines[using]]
這裡的engine其實是:
engines = EngineHandler()
engines.all()是classEngineHandler:的一個方法:
def all(self):
return [self[alias] for alias in self]
這裡for alias in self拆開,迭代對象就是self.templates
def __iter__(self):
return iter(self.templates)
self[alias]拆開就是以self.templates的每一項為key,依次self._getitem__(key)……這裡有有點沒理順。。
def __getitem__(self, alias):
try:
return self._engines[alias]
except KeyError:
try:
params = self.templates[alias]
except KeyError:
raise InvalidTemplateEngineError(
"Could not find config for {} "
"in settings.TEMPLATES".format(alias))
# If importing or initializing the backend raises an exception,
# self._engines[alias] isnt set and this code may get executed
# again, so we must preserve the original params. See #24265.
params = params.copy()
backend = params.pop(BACKEND)
engine_cls = import_string(backend)
engine = engine_cls(params)
self._engines[alias] = engine
return engine
總之,engines = _engine_list(using)獲取了所有引擎(代碼還有點沒看懂),然後engine.get_template(template_name)載入產生了template。
抽取request的信息就是在engine.get_template里完成的
context = make_context(context, request, autoescape=self.backend.engine.autoescape)
具體過程:
https://github.com/django/django/blob/master/django/template/context.py#L265 ?
github.com
def make_context(context, request=None, **kwargs):
"""
Create a suitable Context from a plain dict and optionally an HttpRequest.
"""
if context is not None and not isinstance(context, dict):
raise TypeError(context must be a dict rather than %s. % context.__class__.__name__)
if request is None:
context = Context(context, **kwargs)
else:
# The following pattern is required to ensure values from
# context override those from template context processors.
original_context = context
context = RequestContext(request, **kwargs)
if original_context:
context.push(original_context)
return context
3)最終return template.render(context, request)
這裡的context已經是包含request信息更新的了……
django.template.base | Django documentation | Django ?
docs.djangoproject.com
2、authenticate怎麼做?依據是什麼?
1)is_authenticated是User的一個屬性,只能判斷這個User是不是登錄用戶。
幾乎等效的視圖裝飾器:@login_required
is_authenticated
?
Read-only attribute which is always True
(as opposed toAnonymousUser.is_authenticated
which is always False
). This is a way to tell if the user has been authenticated. This does not imply any permissions and doesn』t check if the user is active or has a valid session. Even though normally you will check this attribute onrequest.user
to find out whether it has been populated by theAuthenticationMiddleware
(representing the currently logged-in user), you should know this attribute is True
for any User
instance.
user要麼是User實例要麼是AnonymousUser,就算is_authenticated==True
,只能證明不是AnonymousUser……並不驗證user is active or has a valid session。所以需要進一步檢查request.user的user這個對象的屬性
Customizing authentication in Django ?
docs.djangoproject.com
Using the Django authentication system ?
docs.djangoproject.com
2)authenticate
(request=None ,**credentials )[source]?
If the given credentials are valid, return a User object.
驗證通過就返回User對象, 否則是None
credentials一般就是username and password,拿著credentials作為關鍵參數一次找每一個backend驗證。只要有1個是valid,就返回User對象;如果全部都不是valid或者只要有1個PermissionDenied, it returns None。
django.contrib.auth | Django documentation | Django
在用戶登錄的時候用到過:
首先驗證表單有效,接著驗證用戶名+密碼有效。條件都滿足,才會調用真正的login函數。
這裡找的backend是默認的django.contrib.auth.backends.ModelBackend(https:// github.com/django/djang o/blob/master/django/conf/global_settings.py#L499 )
順便,settings默認配置在django/conf/global_settings.py
11 def user_login(request):
12 if request.method == "POST":
13 print(request.POST)
14 login_form = LoginForm(request.POST) # requests.POST(dict)
15 if login_form.is_valid():
16 cd = login_form.cleaned_data # cd(dict)
17 user = authenticate(username=cd["username"],password=cd["password"]) #return a User instance if ma tch else None
18 if user:
19 login(request, user) # execute login
20 return HttpResponse("Login~Welcome~")
21 else:
22 return HttpResponse("Fail!Check your username or password")
23 else:
24 return HttpResponse("Invalid data")
3)許可權Permission--暫時沒有用到這個模塊
four default permissions – add, change, delete, and view
Whendjango.contrib.auth
is listed in yourINSTALLED_APPS
setting, 所有註冊app的medels都會支持這個許可權。
Assuming you have an application with an app_label
foo
and a model named Bar
, to test for basic permissions you should use:
add: user.has_perm(foo.add_bar)
change: user.has_perm(foo.change_bar)
delete: user.has_perm(foo.delete_bar)
view: user.has_perm(foo.view_bar)
4)session
session根據保存位置不同有好幾種,對應不同的SESSION_ENGINE:
database-backed sessions
cached sessions
file-based sessions
cookie-based sessions(cookie 會被加密,只有 Server 才知道如何解開)
數據模型在:using the modeldjango.contrib.sessions.models.Session
默認的SESSION_ENGINE=django.contrib.sessions.backends.db,session內容保存在資料庫。
默認配置:
# SESSIONS #
############
# Cache to store session data if using the cache session backend.
SESSION_CACHE_ALIAS = default
# Cookie name. This can be whatever you want.
SESSION_COOKIE_NAME = sessionid
# Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
# A string like "example.com", or None for standard domain cookie.
SESSION_COOKIE_DOMAIN = None
# Whether the session cookie should be secure (https:// only).
SESSION_COOKIE_SECURE = False
# The path of the session cookie.
SESSION_COOKIE_PATH = /
# Whether to use the non-RFC standard httpOnly flag (IE, FF3+, others)
SESSION_COOKIE_HTTPONLY = True
# Whether to set the flag restricting cookie leaks on cross-site requests.
# This can be Lax, Strict, or None to disable the flag.
SESSION_COOKIE_SAMESITE = Lax
# Whether to save the session data on every request.
SESSION_SAVE_EVERY_REQUEST = False
# Whether a users session cookie expires when the Web browser is closed.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
# The module to store session data
SESSION_ENGINE = django.contrib.sessions.backends.db
# Directory to store session files if using the file session module. If None,
# the backend will use a sensible default.
SESSION_FILE_PATH = None
# class to serialize session data
SESSION_SERIALIZER = django.contrib.sessions.serializers.JSONSerializer
How to use sessions
推薦閱讀: