mirror of https://github.com/django/django.git
Refs #27656 -- Updated django.views docstring verbs according to PEP 257.
This commit is contained in:
parent
b23d264046
commit
711123e1cd
|
@ -24,10 +24,11 @@ CLEANSED_SUBSTITUTE = '********************'
|
||||||
|
|
||||||
|
|
||||||
class CallableSettingWrapper:
|
class CallableSettingWrapper:
|
||||||
""" Object to wrap callable appearing in settings
|
"""
|
||||||
|
Object to wrap callable appearing in settings.
|
||||||
* Not to call in the debug page (#21345).
|
* Not to call in the debug page (#21345).
|
||||||
* Not to break the debug page if the callable forbidding to set attributes (#23070).
|
* Not to break the debug page if the callable forbidding to set attributes
|
||||||
|
(#23070).
|
||||||
"""
|
"""
|
||||||
def __init__(self, callable_setting):
|
def __init__(self, callable_setting):
|
||||||
self._wrapped = callable_setting
|
self._wrapped = callable_setting
|
||||||
|
@ -37,10 +38,9 @@ class CallableSettingWrapper:
|
||||||
|
|
||||||
|
|
||||||
def cleanse_setting(key, value):
|
def cleanse_setting(key, value):
|
||||||
"""Cleanse an individual setting key/value of sensitive content.
|
"""
|
||||||
|
Cleanse an individual setting key/value of sensitive content. If the value
|
||||||
If the value is a dictionary, recursively cleanse the keys in
|
is a dictionary, recursively cleanse the keys in that dictionary.
|
||||||
that dictionary.
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if HIDDEN_SETTINGS.search(key):
|
if HIDDEN_SETTINGS.search(key):
|
||||||
|
@ -62,7 +62,10 @@ def cleanse_setting(key, value):
|
||||||
|
|
||||||
|
|
||||||
def get_safe_settings():
|
def get_safe_settings():
|
||||||
"Returns a dictionary of the settings module, with sensitive settings blurred out."
|
"""
|
||||||
|
Return a dictionary of the settings module with values of sensitive
|
||||||
|
settings replaced with stars (*********).
|
||||||
|
"""
|
||||||
settings_dict = {}
|
settings_dict = {}
|
||||||
for k in dir(settings):
|
for k in dir(settings):
|
||||||
if k.isupper():
|
if k.isupper():
|
||||||
|
@ -128,7 +131,7 @@ class SafeExceptionReporterFilter(ExceptionReporterFilter):
|
||||||
|
|
||||||
def get_cleansed_multivaluedict(self, request, multivaluedict):
|
def get_cleansed_multivaluedict(self, request, multivaluedict):
|
||||||
"""
|
"""
|
||||||
Replaces the keys in a MultiValueDict marked as sensitive with stars.
|
Replace the keys in a MultiValueDict marked as sensitive with stars.
|
||||||
This mitigates leaking sensitive POST parameters if something like
|
This mitigates leaking sensitive POST parameters if something like
|
||||||
request.POST['nonexistent_key'] throws an exception (#21098).
|
request.POST['nonexistent_key'] throws an exception (#21098).
|
||||||
"""
|
"""
|
||||||
|
@ -142,7 +145,7 @@ class SafeExceptionReporterFilter(ExceptionReporterFilter):
|
||||||
|
|
||||||
def get_post_parameters(self, request):
|
def get_post_parameters(self, request):
|
||||||
"""
|
"""
|
||||||
Replaces the values of POST parameters marked as sensitive with
|
Replace the values of POST parameters marked as sensitive with
|
||||||
stars (*********).
|
stars (*********).
|
||||||
"""
|
"""
|
||||||
if request is None:
|
if request is None:
|
||||||
|
@ -181,7 +184,7 @@ class SafeExceptionReporterFilter(ExceptionReporterFilter):
|
||||||
|
|
||||||
def get_traceback_frame_variables(self, request, tb_frame):
|
def get_traceback_frame_variables(self, request, tb_frame):
|
||||||
"""
|
"""
|
||||||
Replaces the values of variables marked as sensitive with
|
Replace the values of variables marked as sensitive with
|
||||||
stars (*********).
|
stars (*********).
|
||||||
"""
|
"""
|
||||||
# Loop through the frame's callers to see if the sensitive_variables
|
# Loop through the frame's callers to see if the sensitive_variables
|
||||||
|
@ -231,9 +234,7 @@ class SafeExceptionReporterFilter(ExceptionReporterFilter):
|
||||||
|
|
||||||
|
|
||||||
class ExceptionReporter:
|
class ExceptionReporter:
|
||||||
"""
|
"""Organize and coordinate reporting on exceptions."""
|
||||||
A class to organize and coordinate reporting on exceptions.
|
|
||||||
"""
|
|
||||||
def __init__(self, request, exc_type, exc_value, tb, is_email=False):
|
def __init__(self, request, exc_type, exc_value, tb, is_email=False):
|
||||||
self.request = request
|
self.request = request
|
||||||
self.filter = get_exception_reporter_filter(self.request)
|
self.filter = get_exception_reporter_filter(self.request)
|
||||||
|
@ -318,21 +319,21 @@ class ExceptionReporter:
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def get_traceback_html(self):
|
def get_traceback_html(self):
|
||||||
"Return HTML version of debug 500 HTTP error page."
|
"""Return HTML version of debug 500 HTTP error page."""
|
||||||
t = DEBUG_ENGINE.from_string(TECHNICAL_500_TEMPLATE)
|
t = DEBUG_ENGINE.from_string(TECHNICAL_500_TEMPLATE)
|
||||||
c = Context(self.get_traceback_data(), use_l10n=False)
|
c = Context(self.get_traceback_data(), use_l10n=False)
|
||||||
return t.render(c)
|
return t.render(c)
|
||||||
|
|
||||||
def get_traceback_text(self):
|
def get_traceback_text(self):
|
||||||
"Return plain text version of debug 500 HTTP error page."
|
"""Return plain text version of debug 500 HTTP error page."""
|
||||||
t = DEBUG_ENGINE.from_string(TECHNICAL_500_TEXT_TEMPLATE)
|
t = DEBUG_ENGINE.from_string(TECHNICAL_500_TEXT_TEMPLATE)
|
||||||
c = Context(self.get_traceback_data(), autoescape=False, use_l10n=False)
|
c = Context(self.get_traceback_data(), autoescape=False, use_l10n=False)
|
||||||
return t.render(c)
|
return t.render(c)
|
||||||
|
|
||||||
def _get_lines_from_file(self, filename, lineno, context_lines, loader=None, module_name=None):
|
def _get_lines_from_file(self, filename, lineno, context_lines, loader=None, module_name=None):
|
||||||
"""
|
"""
|
||||||
Returns context_lines before and after lineno from file.
|
Return context_lines before and after lineno from file.
|
||||||
Returns (pre_context_lineno, pre_context, context_line, post_context).
|
Return (pre_context_lineno, pre_context, context_line, post_context).
|
||||||
"""
|
"""
|
||||||
source = None
|
source = None
|
||||||
if loader is not None and hasattr(loader, "get_source"):
|
if loader is not None and hasattr(loader, "get_source"):
|
||||||
|
@ -439,7 +440,7 @@ class ExceptionReporter:
|
||||||
|
|
||||||
|
|
||||||
def technical_404_response(request, exception):
|
def technical_404_response(request, exception):
|
||||||
"Create a technical 404 error response. The exception should be the Http404."
|
"""Create a technical 404 error response. `exception` is the Http404."""
|
||||||
try:
|
try:
|
||||||
error_url = exception.args[0]['path']
|
error_url = exception.args[0]['path']
|
||||||
except (IndexError, TypeError, KeyError):
|
except (IndexError, TypeError, KeyError):
|
||||||
|
@ -494,7 +495,7 @@ def technical_404_response(request, exception):
|
||||||
|
|
||||||
|
|
||||||
def default_urlconf(request):
|
def default_urlconf(request):
|
||||||
"Create an empty URLconf 404 error response."
|
"""Create an empty URLconf 404 error response."""
|
||||||
t = DEBUG_ENGINE.from_string(DEFAULT_URLCONF_TEMPLATE)
|
t = DEBUG_ENGINE.from_string(DEFAULT_URLCONF_TEMPLATE)
|
||||||
c = Context({
|
c = Context({
|
||||||
"title": _("Welcome to Django"),
|
"title": _("Welcome to Django"),
|
||||||
|
|
|
@ -37,8 +37,7 @@ def cache_control(**kwargs):
|
||||||
|
|
||||||
def never_cache(view_func):
|
def never_cache(view_func):
|
||||||
"""
|
"""
|
||||||
Decorator that adds headers to a response so that it will
|
Decorator that adds headers to a response so that it will never be cached.
|
||||||
never be cached.
|
|
||||||
"""
|
"""
|
||||||
@wraps(view_func)
|
@wraps(view_func)
|
||||||
def _wrapped_view_func(request, *args, **kwargs):
|
def _wrapped_view_func(request, *args, **kwargs):
|
||||||
|
|
|
@ -3,11 +3,9 @@ from functools import wraps
|
||||||
|
|
||||||
def xframe_options_deny(view_func):
|
def xframe_options_deny(view_func):
|
||||||
"""
|
"""
|
||||||
Modifies a view function so its response has the X-Frame-Options HTTP
|
Modify a view function so its response has the X-Frame-Options HTTP
|
||||||
header set to 'DENY' as long as the response doesn't already have that
|
header set to 'DENY' as long as the response doesn't already have that
|
||||||
header set.
|
header set. Usage:
|
||||||
|
|
||||||
e.g.
|
|
||||||
|
|
||||||
@xframe_options_deny
|
@xframe_options_deny
|
||||||
def some_view(request):
|
def some_view(request):
|
||||||
|
@ -23,11 +21,9 @@ def xframe_options_deny(view_func):
|
||||||
|
|
||||||
def xframe_options_sameorigin(view_func):
|
def xframe_options_sameorigin(view_func):
|
||||||
"""
|
"""
|
||||||
Modifies a view function so its response has the X-Frame-Options HTTP
|
Modify a view function so its response has the X-Frame-Options HTTP
|
||||||
header set to 'SAMEORIGIN' as long as the response doesn't already have
|
header set to 'SAMEORIGIN' as long as the response doesn't already have
|
||||||
that header set.
|
that header set. Usage:
|
||||||
|
|
||||||
e.g.
|
|
||||||
|
|
||||||
@xframe_options_sameorigin
|
@xframe_options_sameorigin
|
||||||
def some_view(request):
|
def some_view(request):
|
||||||
|
@ -43,10 +39,8 @@ def xframe_options_sameorigin(view_func):
|
||||||
|
|
||||||
def xframe_options_exempt(view_func):
|
def xframe_options_exempt(view_func):
|
||||||
"""
|
"""
|
||||||
Modifies a view function by setting a response variable that instructs
|
Modify a view function by setting a response variable that instructs
|
||||||
XFrameOptionsMiddleware to NOT set the X-Frame-Options HTTP header.
|
XFrameOptionsMiddleware to NOT set the X-Frame-Options HTTP header. Usage:
|
||||||
|
|
||||||
e.g.
|
|
||||||
|
|
||||||
@xframe_options_exempt
|
@xframe_options_exempt
|
||||||
def some_view(request):
|
def some_view(request):
|
||||||
|
|
|
@ -13,8 +13,7 @@ using the decorator multiple times, is harmless and efficient.
|
||||||
|
|
||||||
|
|
||||||
class _EnsureCsrfToken(CsrfViewMiddleware):
|
class _EnsureCsrfToken(CsrfViewMiddleware):
|
||||||
# We need this to behave just like the CsrfViewMiddleware, but not reject
|
# Behave like CsrfViewMiddleware but don't reject requests or log warnings.
|
||||||
# requests or log warnings.
|
|
||||||
def _reject(self, request, reason):
|
def _reject(self, request, reason):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -34,7 +33,7 @@ class _EnsureCsrfCookie(CsrfViewMiddleware):
|
||||||
|
|
||||||
def process_view(self, request, callback, callback_args, callback_kwargs):
|
def process_view(self, request, callback, callback_args, callback_kwargs):
|
||||||
retval = super().process_view(request, callback, callback_args, callback_kwargs)
|
retval = super().process_view(request, callback, callback_args, callback_kwargs)
|
||||||
# Forces process_response to send the cookie
|
# Force process_response to send the cookie
|
||||||
get_token(request)
|
get_token(request)
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
|
@ -48,12 +47,9 @@ uses the csrf_token template tag, or the CsrfViewMiddleware is used.
|
||||||
|
|
||||||
|
|
||||||
def csrf_exempt(view_func):
|
def csrf_exempt(view_func):
|
||||||
"""
|
"""Mark a view function as being exempt from the CSRF view protection."""
|
||||||
Marks a view function as being exempt from the CSRF view protection.
|
# view_func.csrf_exempt = True would also work, but decorators are nicer
|
||||||
"""
|
# if they don't have side effects, so return a new function.
|
||||||
# We could just do view_func.csrf_exempt = True, but decorators
|
|
||||||
# are nicer if they don't have side-effects, so we return a new
|
|
||||||
# function.
|
|
||||||
def wrapped_view(*args, **kwargs):
|
def wrapped_view(*args, **kwargs):
|
||||||
return view_func(*args, **kwargs)
|
return view_func(*args, **kwargs)
|
||||||
wrapped_view.csrf_exempt = True
|
wrapped_view.csrf_exempt = True
|
||||||
|
|
|
@ -5,11 +5,11 @@ from django.http import HttpRequest
|
||||||
|
|
||||||
def sensitive_variables(*variables):
|
def sensitive_variables(*variables):
|
||||||
"""
|
"""
|
||||||
Indicates which variables used in the decorated function are sensitive, so
|
Indicate which variables used in the decorated function are sensitive so
|
||||||
that those variables can later be treated in a special way, for example
|
that those variables can later be treated in a special way, for example
|
||||||
by hiding them when logging unhandled exceptions.
|
by hiding them when logging unhandled exceptions.
|
||||||
|
|
||||||
Two forms are accepted:
|
Accept two forms:
|
||||||
|
|
||||||
* with specified variable names:
|
* with specified variable names:
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ def sensitive_variables(*variables):
|
||||||
credit_card = user.credit_card_number
|
credit_card = user.credit_card_number
|
||||||
...
|
...
|
||||||
|
|
||||||
* without any specified variable names, in which case it is assumed that
|
* without any specified variable names, in which case consider all
|
||||||
all variables are considered sensitive:
|
variables are sensitive:
|
||||||
|
|
||||||
@sensitive_variables()
|
@sensitive_variables()
|
||||||
def my_function()
|
def my_function()
|
||||||
|
@ -40,11 +40,11 @@ def sensitive_variables(*variables):
|
||||||
|
|
||||||
def sensitive_post_parameters(*parameters):
|
def sensitive_post_parameters(*parameters):
|
||||||
"""
|
"""
|
||||||
Indicates which POST parameters used in the decorated view are sensitive,
|
Indicate which POST parameters used in the decorated view are sensitive,
|
||||||
so that those parameters can later be treated in a special way, for example
|
so that those parameters can later be treated in a special way, for example
|
||||||
by hiding them when logging unhandled exceptions.
|
by hiding them when logging unhandled exceptions.
|
||||||
|
|
||||||
Two forms are accepted:
|
Accept two forms:
|
||||||
|
|
||||||
* with specified parameters:
|
* with specified parameters:
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ def sensitive_post_parameters(*parameters):
|
||||||
cc = request.POST['credit_card']
|
cc = request.POST['credit_card']
|
||||||
...
|
...
|
||||||
|
|
||||||
* without any specified parameters, in which case it is assumed that
|
* without any specified parameters, in which case consider all
|
||||||
all parameters are considered sensitive:
|
variables are sensitive:
|
||||||
|
|
||||||
@sensitive_post_parameters()
|
@sensitive_post_parameters()
|
||||||
def my_view(request)
|
def my_view(request)
|
||||||
|
|
|
@ -16,7 +16,7 @@ logger = logging.getLogger('django.request')
|
||||||
class ContextMixin:
|
class ContextMixin:
|
||||||
"""
|
"""
|
||||||
A default context mixin that passes the keyword arguments received by
|
A default context mixin that passes the keyword arguments received by
|
||||||
get_context_data as the template context.
|
get_context_data() as the template context.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -45,9 +45,7 @@ class View:
|
||||||
|
|
||||||
@classonlymethod
|
@classonlymethod
|
||||||
def as_view(cls, **initkwargs):
|
def as_view(cls, **initkwargs):
|
||||||
"""
|
"""Main entry point for a request-response process."""
|
||||||
Main entry point for a request-response process.
|
|
||||||
"""
|
|
||||||
for key in initkwargs:
|
for key in initkwargs:
|
||||||
if key in cls.http_method_names:
|
if key in cls.http_method_names:
|
||||||
raise TypeError("You tried to pass in the %s method name as a "
|
raise TypeError("You tried to pass in the %s method name as a "
|
||||||
|
@ -95,9 +93,7 @@ class View:
|
||||||
return HttpResponseNotAllowed(self._allowed_methods())
|
return HttpResponseNotAllowed(self._allowed_methods())
|
||||||
|
|
||||||
def options(self, request, *args, **kwargs):
|
def options(self, request, *args, **kwargs):
|
||||||
"""
|
"""Handle responding to requests for the OPTIONS HTTP verb."""
|
||||||
Handles responding to requests for the OPTIONS HTTP verb.
|
|
||||||
"""
|
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
response['Allow'] = ', '.join(self._allowed_methods())
|
response['Allow'] = ', '.join(self._allowed_methods())
|
||||||
response['Content-Length'] = '0'
|
response['Content-Length'] = '0'
|
||||||
|
@ -108,9 +104,7 @@ class View:
|
||||||
|
|
||||||
|
|
||||||
class TemplateResponseMixin:
|
class TemplateResponseMixin:
|
||||||
"""
|
"""A mixin that can be used to render a template."""
|
||||||
A mixin that can be used to render a template.
|
|
||||||
"""
|
|
||||||
template_name = None
|
template_name = None
|
||||||
template_engine = None
|
template_engine = None
|
||||||
response_class = TemplateResponse
|
response_class = TemplateResponse
|
||||||
|
@ -118,11 +112,10 @@ class TemplateResponseMixin:
|
||||||
|
|
||||||
def render_to_response(self, context, **response_kwargs):
|
def render_to_response(self, context, **response_kwargs):
|
||||||
"""
|
"""
|
||||||
Returns a response, using the `response_class` for this
|
Return a response, using the `response_class` for this view, with a
|
||||||
view, with a template rendered with the given context.
|
template rendered with the given context.
|
||||||
|
|
||||||
If any keyword arguments are provided, they will be
|
Pass response_kwargs to the constructor of the response class.
|
||||||
passed to the constructor of the response class.
|
|
||||||
"""
|
"""
|
||||||
response_kwargs.setdefault('content_type', self.content_type)
|
response_kwargs.setdefault('content_type', self.content_type)
|
||||||
return self.response_class(
|
return self.response_class(
|
||||||
|
@ -135,8 +128,8 @@ class TemplateResponseMixin:
|
||||||
|
|
||||||
def get_template_names(self):
|
def get_template_names(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of template names to be used for the request. Must return
|
Return a list of template names to be used for the request. Must return
|
||||||
a list. May not be called if render_to_response is overridden.
|
a list. May not be called if render_to_response() is overridden.
|
||||||
"""
|
"""
|
||||||
if self.template_name is None:
|
if self.template_name is None:
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
|
@ -148,8 +141,7 @@ class TemplateResponseMixin:
|
||||||
|
|
||||||
class TemplateView(TemplateResponseMixin, ContextMixin, View):
|
class TemplateView(TemplateResponseMixin, ContextMixin, View):
|
||||||
"""
|
"""
|
||||||
A view that renders a template. This view will also pass into the context
|
Render a template. Pass keyword arguments from the URLconf to the context.
|
||||||
any keyword arguments passed by the URLconf.
|
|
||||||
"""
|
"""
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
context = self.get_context_data(**kwargs)
|
context = self.get_context_data(**kwargs)
|
||||||
|
@ -157,9 +149,7 @@ class TemplateView(TemplateResponseMixin, ContextMixin, View):
|
||||||
|
|
||||||
|
|
||||||
class RedirectView(View):
|
class RedirectView(View):
|
||||||
"""
|
"""Provide a redirect on any GET request."""
|
||||||
A view that provides a redirect on any GET request.
|
|
||||||
"""
|
|
||||||
permanent = False
|
permanent = False
|
||||||
url = None
|
url = None
|
||||||
pattern_name = None
|
pattern_name = None
|
||||||
|
@ -167,9 +157,9 @@ class RedirectView(View):
|
||||||
|
|
||||||
def get_redirect_url(self, *args, **kwargs):
|
def get_redirect_url(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Return the URL redirect to. Keyword arguments from the
|
Return the URL redirect to. Keyword arguments from the URL pattern
|
||||||
URL pattern match generating the redirect request
|
match generating the redirect request are provided as kwargs to this
|
||||||
are provided as kwargs to this method.
|
method.
|
||||||
"""
|
"""
|
||||||
if self.url:
|
if self.url:
|
||||||
url = self.url % kwargs
|
url = self.url % kwargs
|
||||||
|
|
|
@ -18,9 +18,7 @@ from django.views.generic.list import (
|
||||||
|
|
||||||
|
|
||||||
class YearMixin:
|
class YearMixin:
|
||||||
"""
|
"""Mixin for views manipulating year-based data."""
|
||||||
Mixin for views manipulating year-based data.
|
|
||||||
"""
|
|
||||||
year_format = '%Y'
|
year_format = '%Y'
|
||||||
year = None
|
year = None
|
||||||
|
|
||||||
|
@ -32,9 +30,7 @@ class YearMixin:
|
||||||
return self.year_format
|
return self.year_format
|
||||||
|
|
||||||
def get_year(self):
|
def get_year(self):
|
||||||
"""
|
"""Return the year for which this view should display data."""
|
||||||
Return the year for which this view should display data.
|
|
||||||
"""
|
|
||||||
year = self.year
|
year = self.year
|
||||||
if year is None:
|
if year is None:
|
||||||
try:
|
try:
|
||||||
|
@ -47,15 +43,11 @@ class YearMixin:
|
||||||
return year
|
return year
|
||||||
|
|
||||||
def get_next_year(self, date):
|
def get_next_year(self, date):
|
||||||
"""
|
"""Get the next valid year."""
|
||||||
Get the next valid year.
|
|
||||||
"""
|
|
||||||
return _get_next_prev(self, date, is_previous=False, period='year')
|
return _get_next_prev(self, date, is_previous=False, period='year')
|
||||||
|
|
||||||
def get_previous_year(self, date):
|
def get_previous_year(self, date):
|
||||||
"""
|
"""Get the previous valid year."""
|
||||||
Get the previous valid year.
|
|
||||||
"""
|
|
||||||
return _get_next_prev(self, date, is_previous=True, period='year')
|
return _get_next_prev(self, date, is_previous=True, period='year')
|
||||||
|
|
||||||
def _get_next_year(self, date):
|
def _get_next_year(self, date):
|
||||||
|
@ -67,16 +59,12 @@ class YearMixin:
|
||||||
return date.replace(year=date.year + 1, month=1, day=1)
|
return date.replace(year=date.year + 1, month=1, day=1)
|
||||||
|
|
||||||
def _get_current_year(self, date):
|
def _get_current_year(self, date):
|
||||||
"""
|
"""Return the start date of the current interval."""
|
||||||
Return the start date of the current interval.
|
|
||||||
"""
|
|
||||||
return date.replace(month=1, day=1)
|
return date.replace(month=1, day=1)
|
||||||
|
|
||||||
|
|
||||||
class MonthMixin:
|
class MonthMixin:
|
||||||
"""
|
"""Mixin for views manipulating month-based data."""
|
||||||
Mixin for views manipulating month-based data.
|
|
||||||
"""
|
|
||||||
month_format = '%b'
|
month_format = '%b'
|
||||||
month = None
|
month = None
|
||||||
|
|
||||||
|
@ -88,9 +76,7 @@ class MonthMixin:
|
||||||
return self.month_format
|
return self.month_format
|
||||||
|
|
||||||
def get_month(self):
|
def get_month(self):
|
||||||
"""
|
"""Return the month for which this view should display data."""
|
||||||
Return the month for which this view should display data.
|
|
||||||
"""
|
|
||||||
month = self.month
|
month = self.month
|
||||||
if month is None:
|
if month is None:
|
||||||
try:
|
try:
|
||||||
|
@ -103,15 +89,11 @@ class MonthMixin:
|
||||||
return month
|
return month
|
||||||
|
|
||||||
def get_next_month(self, date):
|
def get_next_month(self, date):
|
||||||
"""
|
"""Get the next valid month."""
|
||||||
Get the next valid month.
|
|
||||||
"""
|
|
||||||
return _get_next_prev(self, date, is_previous=False, period='month')
|
return _get_next_prev(self, date, is_previous=False, period='month')
|
||||||
|
|
||||||
def get_previous_month(self, date):
|
def get_previous_month(self, date):
|
||||||
"""
|
"""Get the previous valid month."""
|
||||||
Get the previous valid month.
|
|
||||||
"""
|
|
||||||
return _get_next_prev(self, date, is_previous=True, period='month')
|
return _get_next_prev(self, date, is_previous=True, period='month')
|
||||||
|
|
||||||
def _get_next_month(self, date):
|
def _get_next_month(self, date):
|
||||||
|
@ -126,16 +108,12 @@ class MonthMixin:
|
||||||
return date.replace(month=date.month + 1, day=1)
|
return date.replace(month=date.month + 1, day=1)
|
||||||
|
|
||||||
def _get_current_month(self, date):
|
def _get_current_month(self, date):
|
||||||
"""
|
"""Return the start date of the previous interval."""
|
||||||
Return the start date of the previous interval.
|
|
||||||
"""
|
|
||||||
return date.replace(day=1)
|
return date.replace(day=1)
|
||||||
|
|
||||||
|
|
||||||
class DayMixin:
|
class DayMixin:
|
||||||
"""
|
"""Mixin for views manipulating day-based data."""
|
||||||
Mixin for views manipulating day-based data.
|
|
||||||
"""
|
|
||||||
day_format = '%d'
|
day_format = '%d'
|
||||||
day = None
|
day = None
|
||||||
|
|
||||||
|
@ -147,9 +125,7 @@ class DayMixin:
|
||||||
return self.day_format
|
return self.day_format
|
||||||
|
|
||||||
def get_day(self):
|
def get_day(self):
|
||||||
"""
|
"""Return the day for which this view should display data."""
|
||||||
Return the day for which this view should display data.
|
|
||||||
"""
|
|
||||||
day = self.day
|
day = self.day
|
||||||
if day is None:
|
if day is None:
|
||||||
try:
|
try:
|
||||||
|
@ -162,15 +138,11 @@ class DayMixin:
|
||||||
return day
|
return day
|
||||||
|
|
||||||
def get_next_day(self, date):
|
def get_next_day(self, date):
|
||||||
"""
|
"""Get the next valid day."""
|
||||||
Get the next valid day.
|
|
||||||
"""
|
|
||||||
return _get_next_prev(self, date, is_previous=False, period='day')
|
return _get_next_prev(self, date, is_previous=False, period='day')
|
||||||
|
|
||||||
def get_previous_day(self, date):
|
def get_previous_day(self, date):
|
||||||
"""
|
"""Get the previous valid day."""
|
||||||
Get the previous valid day.
|
|
||||||
"""
|
|
||||||
return _get_next_prev(self, date, is_previous=True, period='day')
|
return _get_next_prev(self, date, is_previous=True, period='day')
|
||||||
|
|
||||||
def _get_next_day(self, date):
|
def _get_next_day(self, date):
|
||||||
|
@ -182,16 +154,12 @@ class DayMixin:
|
||||||
return date + datetime.timedelta(days=1)
|
return date + datetime.timedelta(days=1)
|
||||||
|
|
||||||
def _get_current_day(self, date):
|
def _get_current_day(self, date):
|
||||||
"""
|
"""Return the start date of the current interval."""
|
||||||
Return the start date of the current interval.
|
|
||||||
"""
|
|
||||||
return date
|
return date
|
||||||
|
|
||||||
|
|
||||||
class WeekMixin:
|
class WeekMixin:
|
||||||
"""
|
"""Mixin for views manipulating week-based data."""
|
||||||
Mixin for views manipulating week-based data.
|
|
||||||
"""
|
|
||||||
week_format = '%U'
|
week_format = '%U'
|
||||||
week = None
|
week = None
|
||||||
|
|
||||||
|
@ -203,9 +171,7 @@ class WeekMixin:
|
||||||
return self.week_format
|
return self.week_format
|
||||||
|
|
||||||
def get_week(self):
|
def get_week(self):
|
||||||
"""
|
"""Return the week for which this view should display data."""
|
||||||
Return the week for which this view should display data
|
|
||||||
"""
|
|
||||||
week = self.week
|
week = self.week
|
||||||
if week is None:
|
if week is None:
|
||||||
try:
|
try:
|
||||||
|
@ -218,15 +184,11 @@ class WeekMixin:
|
||||||
return week
|
return week
|
||||||
|
|
||||||
def get_next_week(self, date):
|
def get_next_week(self, date):
|
||||||
"""
|
"""Get the next valid week."""
|
||||||
Get the next valid week.
|
|
||||||
"""
|
|
||||||
return _get_next_prev(self, date, is_previous=False, period='week')
|
return _get_next_prev(self, date, is_previous=False, period='week')
|
||||||
|
|
||||||
def get_previous_week(self, date):
|
def get_previous_week(self, date):
|
||||||
"""
|
"""Get the previous valid week."""
|
||||||
Get the previous valid week.
|
|
||||||
"""
|
|
||||||
return _get_next_prev(self, date, is_previous=True, period='week')
|
return _get_next_prev(self, date, is_previous=True, period='week')
|
||||||
|
|
||||||
def _get_next_week(self, date):
|
def _get_next_week(self, date):
|
||||||
|
@ -238,9 +200,7 @@ class WeekMixin:
|
||||||
return date + datetime.timedelta(days=7 - self._get_weekday(date))
|
return date + datetime.timedelta(days=7 - self._get_weekday(date))
|
||||||
|
|
||||||
def _get_current_week(self, date):
|
def _get_current_week(self, date):
|
||||||
"""
|
"""Return the start date of the current interval."""
|
||||||
Return the start date of the current interval.
|
|
||||||
"""
|
|
||||||
return date - datetime.timedelta(self._get_weekday(date))
|
return date - datetime.timedelta(self._get_weekday(date))
|
||||||
|
|
||||||
def _get_weekday(self, date):
|
def _get_weekday(self, date):
|
||||||
|
@ -259,23 +219,19 @@ class WeekMixin:
|
||||||
|
|
||||||
|
|
||||||
class DateMixin:
|
class DateMixin:
|
||||||
"""
|
"""Mixin class for views manipulating date-based data."""
|
||||||
Mixin class for views manipulating date-based data.
|
|
||||||
"""
|
|
||||||
date_field = None
|
date_field = None
|
||||||
allow_future = False
|
allow_future = False
|
||||||
|
|
||||||
def get_date_field(self):
|
def get_date_field(self):
|
||||||
"""
|
"""Get the name of the date field to be used to filter by."""
|
||||||
Get the name of the date field to be used to filter by.
|
|
||||||
"""
|
|
||||||
if self.date_field is None:
|
if self.date_field is None:
|
||||||
raise ImproperlyConfigured("%s.date_field is required." % self.__class__.__name__)
|
raise ImproperlyConfigured("%s.date_field is required." % self.__class__.__name__)
|
||||||
return self.date_field
|
return self.date_field
|
||||||
|
|
||||||
def get_allow_future(self):
|
def get_allow_future(self):
|
||||||
"""
|
"""
|
||||||
Returns `True` if the view should be allowed to display objects from
|
Return `True` if the view should be allowed to display objects from
|
||||||
the future.
|
the future.
|
||||||
"""
|
"""
|
||||||
return self.allow_future
|
return self.allow_future
|
||||||
|
@ -327,9 +283,7 @@ class DateMixin:
|
||||||
|
|
||||||
|
|
||||||
class BaseDateListView(MultipleObjectMixin, DateMixin, View):
|
class BaseDateListView(MultipleObjectMixin, DateMixin, View):
|
||||||
"""
|
"""Abstract base class for date-based views displaying a list of objects."""
|
||||||
Abstract base class for date-based views displaying a list of objects.
|
|
||||||
"""
|
|
||||||
allow_empty = False
|
allow_empty = False
|
||||||
date_list_period = 'year'
|
date_list_period = 'year'
|
||||||
|
|
||||||
|
@ -341,14 +295,12 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View):
|
||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
|
|
||||||
def get_dated_items(self):
|
def get_dated_items(self):
|
||||||
"""
|
"""Obtain the list of dates and items."""
|
||||||
Obtain the list of dates and items.
|
|
||||||
"""
|
|
||||||
raise NotImplementedError('A DateView must provide an implementation of get_dated_items()')
|
raise NotImplementedError('A DateView must provide an implementation of get_dated_items()')
|
||||||
|
|
||||||
def get_ordering(self):
|
def get_ordering(self):
|
||||||
"""
|
"""
|
||||||
Returns the field or fields to use for ordering the queryset; uses the
|
Return the field or fields to use for ordering the queryset; use the
|
||||||
date field by default.
|
date field by default.
|
||||||
"""
|
"""
|
||||||
return '-%s' % self.get_date_field() if self.ordering is None else self.ordering
|
return '-%s' % self.get_date_field() if self.ordering is None else self.ordering
|
||||||
|
@ -381,7 +333,8 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View):
|
||||||
|
|
||||||
def get_date_list_period(self):
|
def get_date_list_period(self):
|
||||||
"""
|
"""
|
||||||
Get the aggregation period for the list of dates: 'year', 'month', or 'day'.
|
Get the aggregation period for the list of dates: 'year', 'month', or
|
||||||
|
'day'.
|
||||||
"""
|
"""
|
||||||
return self.date_list_period
|
return self.date_list_period
|
||||||
|
|
||||||
|
@ -409,16 +362,12 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View):
|
||||||
|
|
||||||
class BaseArchiveIndexView(BaseDateListView):
|
class BaseArchiveIndexView(BaseDateListView):
|
||||||
"""
|
"""
|
||||||
Base class for archives of date-based items.
|
Base class for archives of date-based items. Requires a response mixin.
|
||||||
|
|
||||||
Requires a response mixin.
|
|
||||||
"""
|
"""
|
||||||
context_object_name = 'latest'
|
context_object_name = 'latest'
|
||||||
|
|
||||||
def get_dated_items(self):
|
def get_dated_items(self):
|
||||||
"""
|
"""Return (date_list, items, extra_context) for this request."""
|
||||||
Return (date_list, items, extra_context) for this request.
|
|
||||||
"""
|
|
||||||
qs = self.get_dated_queryset()
|
qs = self.get_dated_queryset()
|
||||||
date_list = self.get_date_list(qs, ordering='DESC')
|
date_list = self.get_date_list(qs, ordering='DESC')
|
||||||
|
|
||||||
|
@ -429,23 +378,17 @@ class BaseArchiveIndexView(BaseDateListView):
|
||||||
|
|
||||||
|
|
||||||
class ArchiveIndexView(MultipleObjectTemplateResponseMixin, BaseArchiveIndexView):
|
class ArchiveIndexView(MultipleObjectTemplateResponseMixin, BaseArchiveIndexView):
|
||||||
"""
|
"""Top-level archive of date-based items."""
|
||||||
Top-level archive of date-based items.
|
|
||||||
"""
|
|
||||||
template_name_suffix = '_archive'
|
template_name_suffix = '_archive'
|
||||||
|
|
||||||
|
|
||||||
class BaseYearArchiveView(YearMixin, BaseDateListView):
|
class BaseYearArchiveView(YearMixin, BaseDateListView):
|
||||||
"""
|
"""List of objects published in a given year."""
|
||||||
List of objects published in a given year.
|
|
||||||
"""
|
|
||||||
date_list_period = 'month'
|
date_list_period = 'month'
|
||||||
make_object_list = False
|
make_object_list = False
|
||||||
|
|
||||||
def get_dated_items(self):
|
def get_dated_items(self):
|
||||||
"""
|
"""Return (date_list, items, extra_context) for this request."""
|
||||||
Return (date_list, items, extra_context) for this request.
|
|
||||||
"""
|
|
||||||
year = self.get_year()
|
year = self.get_year()
|
||||||
|
|
||||||
date_field = self.get_date_field()
|
date_field = self.get_date_field()
|
||||||
|
@ -481,22 +424,16 @@ class BaseYearArchiveView(YearMixin, BaseDateListView):
|
||||||
|
|
||||||
|
|
||||||
class YearArchiveView(MultipleObjectTemplateResponseMixin, BaseYearArchiveView):
|
class YearArchiveView(MultipleObjectTemplateResponseMixin, BaseYearArchiveView):
|
||||||
"""
|
"""List of objects published in a given year."""
|
||||||
List of objects published in a given year.
|
|
||||||
"""
|
|
||||||
template_name_suffix = '_archive_year'
|
template_name_suffix = '_archive_year'
|
||||||
|
|
||||||
|
|
||||||
class BaseMonthArchiveView(YearMixin, MonthMixin, BaseDateListView):
|
class BaseMonthArchiveView(YearMixin, MonthMixin, BaseDateListView):
|
||||||
"""
|
"""List of objects published in a given month."""
|
||||||
List of objects published in a given month.
|
|
||||||
"""
|
|
||||||
date_list_period = 'day'
|
date_list_period = 'day'
|
||||||
|
|
||||||
def get_dated_items(self):
|
def get_dated_items(self):
|
||||||
"""
|
"""Return (date_list, items, extra_context) for this request."""
|
||||||
Return (date_list, items, extra_context) for this request.
|
|
||||||
"""
|
|
||||||
year = self.get_year()
|
year = self.get_year()
|
||||||
month = self.get_month()
|
month = self.get_month()
|
||||||
|
|
||||||
|
@ -522,21 +459,15 @@ class BaseMonthArchiveView(YearMixin, MonthMixin, BaseDateListView):
|
||||||
|
|
||||||
|
|
||||||
class MonthArchiveView(MultipleObjectTemplateResponseMixin, BaseMonthArchiveView):
|
class MonthArchiveView(MultipleObjectTemplateResponseMixin, BaseMonthArchiveView):
|
||||||
"""
|
"""List of objects published in a given month."""
|
||||||
List of objects published in a given month.
|
|
||||||
"""
|
|
||||||
template_name_suffix = '_archive_month'
|
template_name_suffix = '_archive_month'
|
||||||
|
|
||||||
|
|
||||||
class BaseWeekArchiveView(YearMixin, WeekMixin, BaseDateListView):
|
class BaseWeekArchiveView(YearMixin, WeekMixin, BaseDateListView):
|
||||||
"""
|
"""List of objects published in a given week."""
|
||||||
List of objects published in a given week.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def get_dated_items(self):
|
def get_dated_items(self):
|
||||||
"""
|
"""Return (date_list, items, extra_context) for this request."""
|
||||||
Return (date_list, items, extra_context) for this request.
|
|
||||||
"""
|
|
||||||
year = self.get_year()
|
year = self.get_year()
|
||||||
week = self.get_week()
|
week = self.get_week()
|
||||||
|
|
||||||
|
@ -567,20 +498,14 @@ class BaseWeekArchiveView(YearMixin, WeekMixin, BaseDateListView):
|
||||||
|
|
||||||
|
|
||||||
class WeekArchiveView(MultipleObjectTemplateResponseMixin, BaseWeekArchiveView):
|
class WeekArchiveView(MultipleObjectTemplateResponseMixin, BaseWeekArchiveView):
|
||||||
"""
|
"""List of objects published in a given week."""
|
||||||
List of objects published in a given week.
|
|
||||||
"""
|
|
||||||
template_name_suffix = '_archive_week'
|
template_name_suffix = '_archive_week'
|
||||||
|
|
||||||
|
|
||||||
class BaseDayArchiveView(YearMixin, MonthMixin, DayMixin, BaseDateListView):
|
class BaseDayArchiveView(YearMixin, MonthMixin, DayMixin, BaseDateListView):
|
||||||
"""
|
"""List of objects published on a given day."""
|
||||||
List of objects published on a given day.
|
|
||||||
"""
|
|
||||||
def get_dated_items(self):
|
def get_dated_items(self):
|
||||||
"""
|
"""Return (date_list, items, extra_context) for this request."""
|
||||||
Return (date_list, items, extra_context) for this request.
|
|
||||||
"""
|
|
||||||
year = self.get_year()
|
year = self.get_year()
|
||||||
month = self.get_month()
|
month = self.get_month()
|
||||||
day = self.get_day()
|
day = self.get_day()
|
||||||
|
@ -609,28 +534,20 @@ class BaseDayArchiveView(YearMixin, MonthMixin, DayMixin, BaseDateListView):
|
||||||
|
|
||||||
|
|
||||||
class DayArchiveView(MultipleObjectTemplateResponseMixin, BaseDayArchiveView):
|
class DayArchiveView(MultipleObjectTemplateResponseMixin, BaseDayArchiveView):
|
||||||
"""
|
"""List of objects published on a given day."""
|
||||||
List of objects published on a given day.
|
|
||||||
"""
|
|
||||||
template_name_suffix = "_archive_day"
|
template_name_suffix = "_archive_day"
|
||||||
|
|
||||||
|
|
||||||
class BaseTodayArchiveView(BaseDayArchiveView):
|
class BaseTodayArchiveView(BaseDayArchiveView):
|
||||||
"""
|
"""List of objects published today."""
|
||||||
List of objects published today.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def get_dated_items(self):
|
def get_dated_items(self):
|
||||||
"""
|
"""Return (date_list, items, extra_context) for this request."""
|
||||||
Return (date_list, items, extra_context) for this request.
|
|
||||||
"""
|
|
||||||
return self._get_dated_items(datetime.date.today())
|
return self._get_dated_items(datetime.date.today())
|
||||||
|
|
||||||
|
|
||||||
class TodayArchiveView(MultipleObjectTemplateResponseMixin, BaseTodayArchiveView):
|
class TodayArchiveView(MultipleObjectTemplateResponseMixin, BaseTodayArchiveView):
|
||||||
"""
|
"""List of objects published today."""
|
||||||
List of objects published today.
|
|
||||||
"""
|
|
||||||
template_name_suffix = "_archive_day"
|
template_name_suffix = "_archive_day"
|
||||||
|
|
||||||
|
|
||||||
|
@ -640,9 +557,7 @@ class BaseDateDetailView(YearMixin, MonthMixin, DayMixin, DateMixin, BaseDetailV
|
||||||
standard DetailView by accepting a year/month/day in the URL.
|
standard DetailView by accepting a year/month/day in the URL.
|
||||||
"""
|
"""
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
"""
|
"""Get the object this request displays."""
|
||||||
Get the object this request displays.
|
|
||||||
"""
|
|
||||||
year = self.get_year()
|
year = self.get_year()
|
||||||
month = self.get_month()
|
month = self.get_month()
|
||||||
day = self.get_day()
|
day = self.get_day()
|
||||||
|
@ -681,8 +596,8 @@ class DateDetailView(SingleObjectTemplateResponseMixin, BaseDateDetailView):
|
||||||
|
|
||||||
def _date_from_string(year, year_format, month='', month_format='', day='', day_format='', delim='__'):
|
def _date_from_string(year, year_format, month='', month_format='', day='', day_format='', delim='__'):
|
||||||
"""
|
"""
|
||||||
Helper: get a datetime.date object given a format string and a year,
|
Get a datetime.date object given a format string and a year, month, and day
|
||||||
month, and day (only year is mandatory). Raise a 404 for an invalid date.
|
(only year is mandatory). Raise a 404 for an invalid date.
|
||||||
"""
|
"""
|
||||||
format = delim.join((year_format, month_format, day_format))
|
format = delim.join((year_format, month_format, day_format))
|
||||||
datestr = delim.join((year, month, day))
|
datestr = delim.join((year, month, day))
|
||||||
|
@ -697,9 +612,9 @@ def _date_from_string(year, year_format, month='', month_format='', day='', day_
|
||||||
|
|
||||||
def _get_next_prev(generic_view, date, is_previous, period):
|
def _get_next_prev(generic_view, date, is_previous, period):
|
||||||
"""
|
"""
|
||||||
Helper: Get the next or the previous valid date. The idea is to allow
|
Get the next or the previous valid date. The idea is to allow links on
|
||||||
links on month/day views to never be 404s by never providing a date
|
month/day views to never be 404s by never providing a date that'll be
|
||||||
that'll be invalid for the given view.
|
invalid for the given view.
|
||||||
|
|
||||||
This is a bit complicated since it handles different intervals of time,
|
This is a bit complicated since it handles different intervals of time,
|
||||||
hence the coupling to generic_view.
|
hence the coupling to generic_view.
|
||||||
|
@ -786,9 +701,7 @@ def _get_next_prev(generic_view, date, is_previous, period):
|
||||||
|
|
||||||
|
|
||||||
def timezone_today():
|
def timezone_today():
|
||||||
"""
|
"""Return the current date in the current time zone."""
|
||||||
Return the current date in the current time zone.
|
|
||||||
"""
|
|
||||||
if settings.USE_TZ:
|
if settings.USE_TZ:
|
||||||
return timezone.localdate()
|
return timezone.localdate()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
|
||||||
|
|
||||||
class SingleObjectMixin(ContextMixin):
|
class SingleObjectMixin(ContextMixin):
|
||||||
"""
|
"""
|
||||||
Provides the ability to retrieve a single object for further manipulation.
|
Provide the ability to retrieve a single object for further manipulation.
|
||||||
"""
|
"""
|
||||||
model = None
|
model = None
|
||||||
queryset = None
|
queryset = None
|
||||||
|
@ -19,10 +19,10 @@ class SingleObjectMixin(ContextMixin):
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
"""
|
"""
|
||||||
Returns the object the view is displaying.
|
Return the object the view is displaying.
|
||||||
|
|
||||||
By default this requires `self.queryset` and a `pk` or `slug` argument
|
Require `self.queryset` and a `pk` or `slug` argument in the URLconf.
|
||||||
in the URLconf, but subclasses can override this to return any object.
|
Subclasses can override this to return any object.
|
||||||
"""
|
"""
|
||||||
# Use a custom queryset if provided; this is required for subclasses
|
# Use a custom queryset if provided; this is required for subclasses
|
||||||
# like DateDetailView
|
# like DateDetailView
|
||||||
|
@ -58,8 +58,8 @@ class SingleObjectMixin(ContextMixin):
|
||||||
"""
|
"""
|
||||||
Return the `QuerySet` that will be used to look up the object.
|
Return the `QuerySet` that will be used to look up the object.
|
||||||
|
|
||||||
Note that this method is called by the default implementation of
|
This method is called by the default implementation of get_object() and
|
||||||
`get_object` and may not be called if `get_object` is overridden.
|
may not be called if get_object() is overridden.
|
||||||
"""
|
"""
|
||||||
if self.queryset is None:
|
if self.queryset is None:
|
||||||
if self.model:
|
if self.model:
|
||||||
|
@ -75,15 +75,11 @@ class SingleObjectMixin(ContextMixin):
|
||||||
return self.queryset.all()
|
return self.queryset.all()
|
||||||
|
|
||||||
def get_slug_field(self):
|
def get_slug_field(self):
|
||||||
"""
|
"""Get the name of a slug field to be used to look up by slug."""
|
||||||
Get the name of a slug field to be used to look up by slug.
|
|
||||||
"""
|
|
||||||
return self.slug_field
|
return self.slug_field
|
||||||
|
|
||||||
def get_context_object_name(self, obj):
|
def get_context_object_name(self, obj):
|
||||||
"""
|
"""Get the name to use for the object."""
|
||||||
Get the name to use for the object.
|
|
||||||
"""
|
|
||||||
if self.context_object_name:
|
if self.context_object_name:
|
||||||
return self.context_object_name
|
return self.context_object_name
|
||||||
elif isinstance(obj, models.Model):
|
elif isinstance(obj, models.Model):
|
||||||
|
@ -92,9 +88,7 @@ class SingleObjectMixin(ContextMixin):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""
|
"""Insert the single object into the context dict."""
|
||||||
Insert the single object into the context dict.
|
|
||||||
"""
|
|
||||||
context = {}
|
context = {}
|
||||||
if self.object:
|
if self.object:
|
||||||
context['object'] = self.object
|
context['object'] = self.object
|
||||||
|
@ -106,9 +100,7 @@ class SingleObjectMixin(ContextMixin):
|
||||||
|
|
||||||
|
|
||||||
class BaseDetailView(SingleObjectMixin, View):
|
class BaseDetailView(SingleObjectMixin, View):
|
||||||
"""
|
"""A base view for displaying a single object."""
|
||||||
A base view for displaying a single object
|
|
||||||
"""
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
context = self.get_context_data(object=self.object)
|
context = self.get_context_data(object=self.object)
|
||||||
|
@ -122,7 +114,7 @@ class SingleObjectTemplateResponseMixin(TemplateResponseMixin):
|
||||||
def get_template_names(self):
|
def get_template_names(self):
|
||||||
"""
|
"""
|
||||||
Return a list of template names to be used for the request. May not be
|
Return a list of template names to be used for the request. May not be
|
||||||
called if render_to_response is overridden. Returns the following list:
|
called if render_to_response() is overridden. Return the following list:
|
||||||
|
|
||||||
* the value of ``template_name`` on the view (if provided)
|
* the value of ``template_name`` on the view (if provided)
|
||||||
* the contents of the ``template_name_field`` field on the
|
* the contents of the ``template_name_field`` field on the
|
||||||
|
|
|
@ -9,45 +9,32 @@ from django.views.generic.detail import (
|
||||||
|
|
||||||
|
|
||||||
class FormMixin(ContextMixin):
|
class FormMixin(ContextMixin):
|
||||||
"""
|
"""Provide a way to show and handle a form in a request."""
|
||||||
A mixin that provides a way to show and handle a form in a request.
|
|
||||||
"""
|
|
||||||
|
|
||||||
initial = {}
|
initial = {}
|
||||||
form_class = None
|
form_class = None
|
||||||
success_url = None
|
success_url = None
|
||||||
prefix = None
|
prefix = None
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
"""
|
"""Return the initial data to use for forms on this view."""
|
||||||
Returns the initial data to use for forms on this view.
|
|
||||||
"""
|
|
||||||
return self.initial.copy()
|
return self.initial.copy()
|
||||||
|
|
||||||
def get_prefix(self):
|
def get_prefix(self):
|
||||||
"""
|
"""Return the prefix to use for forms."""
|
||||||
Returns the prefix to use for forms on this view
|
|
||||||
"""
|
|
||||||
return self.prefix
|
return self.prefix
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
"""
|
"""Return the form class to use."""
|
||||||
Returns the form class to use in this view
|
|
||||||
"""
|
|
||||||
return self.form_class
|
return self.form_class
|
||||||
|
|
||||||
def get_form(self, form_class=None):
|
def get_form(self, form_class=None):
|
||||||
"""
|
"""Return an instance of the form to be used in this view."""
|
||||||
Returns an instance of the form to be used in this view.
|
|
||||||
"""
|
|
||||||
if form_class is None:
|
if form_class is None:
|
||||||
form_class = self.get_form_class()
|
form_class = self.get_form_class()
|
||||||
return form_class(**self.get_form_kwargs())
|
return form_class(**self.get_form_kwargs())
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
"""
|
"""Return the keyword arguments for instantiating the form."""
|
||||||
Returns the keyword arguments for instantiating the form.
|
|
||||||
"""
|
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'initial': self.get_initial(),
|
'initial': self.get_initial(),
|
||||||
'prefix': self.get_prefix(),
|
'prefix': self.get_prefix(),
|
||||||
|
@ -61,9 +48,7 @@ class FormMixin(ContextMixin):
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
"""
|
"""Return the URL to redirect to after processing a valid form."""
|
||||||
Returns the supplied success URL.
|
|
||||||
"""
|
|
||||||
if self.success_url:
|
if self.success_url:
|
||||||
# Forcing possible reverse_lazy evaluation
|
# Forcing possible reverse_lazy evaluation
|
||||||
url = force_text(self.success_url)
|
url = force_text(self.success_url)
|
||||||
|
@ -73,37 +58,26 @@ class FormMixin(ContextMixin):
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""If the form is valid, redirect to the supplied URL."""
|
||||||
If the form is valid, redirect to the supplied URL.
|
|
||||||
"""
|
|
||||||
return HttpResponseRedirect(self.get_success_url())
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
|
|
||||||
def form_invalid(self, form):
|
def form_invalid(self, form):
|
||||||
"""
|
"""If the form is invalid, render the invalid form."""
|
||||||
If the form is invalid, re-render the context data with the
|
|
||||||
data-filled form and errors.
|
|
||||||
"""
|
|
||||||
return self.render_to_response(self.get_context_data(form=form))
|
return self.render_to_response(self.get_context_data(form=form))
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""
|
"""Insert the form into the context dict."""
|
||||||
Insert the form into the context dict.
|
|
||||||
"""
|
|
||||||
if 'form' not in kwargs:
|
if 'form' not in kwargs:
|
||||||
kwargs['form'] = self.get_form()
|
kwargs['form'] = self.get_form()
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ModelFormMixin(FormMixin, SingleObjectMixin):
|
class ModelFormMixin(FormMixin, SingleObjectMixin):
|
||||||
"""
|
"""Provide a way to show and handle a ModelForm in a request."""
|
||||||
A mixin that provides a way to show and handle a modelform in a request.
|
|
||||||
"""
|
|
||||||
fields = None
|
fields = None
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
"""
|
"""Return the form class to use in this view."""
|
||||||
Returns the form class to use in this view.
|
|
||||||
"""
|
|
||||||
if self.fields is not None and self.form_class:
|
if self.fields is not None and self.form_class:
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
"Specifying both 'fields' and 'form_class' is not permitted."
|
"Specifying both 'fields' and 'form_class' is not permitted."
|
||||||
|
@ -132,18 +106,14 @@ class ModelFormMixin(FormMixin, SingleObjectMixin):
|
||||||
return model_forms.modelform_factory(model, fields=self.fields)
|
return model_forms.modelform_factory(model, fields=self.fields)
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
"""
|
"""Return the keyword arguments for instantiating the form."""
|
||||||
Returns the keyword arguments for instantiating the form.
|
|
||||||
"""
|
|
||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
if hasattr(self, 'object'):
|
if hasattr(self, 'object'):
|
||||||
kwargs.update({'instance': self.object})
|
kwargs.update({'instance': self.object})
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
"""
|
"""Return the URL to redirect to after processing a valid form."""
|
||||||
Returns the supplied URL.
|
|
||||||
"""
|
|
||||||
if self.success_url:
|
if self.success_url:
|
||||||
url = self.success_url.format(**self.object.__dict__)
|
url = self.success_url.format(**self.object.__dict__)
|
||||||
else:
|
else:
|
||||||
|
@ -156,27 +126,21 @@ class ModelFormMixin(FormMixin, SingleObjectMixin):
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""If the form is valid, save the associated model."""
|
||||||
If the form is valid, save the associated model.
|
|
||||||
"""
|
|
||||||
self.object = form.save()
|
self.object = form.save()
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class ProcessFormView(View):
|
class ProcessFormView(View):
|
||||||
"""
|
"""Render a form on GET and processes it on POST."""
|
||||||
A mixin that renders a form on GET and processes it on POST.
|
|
||||||
"""
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
"""
|
"""Handle GET requests: instantiate a blank version of the form."""
|
||||||
Handles GET requests and instantiates a blank version of the form.
|
|
||||||
"""
|
|
||||||
return self.render_to_response(self.get_context_data())
|
return self.render_to_response(self.get_context_data())
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Handles POST requests, instantiating a form instance with the passed
|
Handle POST requests: instantiate a form instance with the passed
|
||||||
POST variables and then checked for validity.
|
POST variables and then check if it's valid.
|
||||||
"""
|
"""
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
@ -191,15 +155,11 @@ class ProcessFormView(View):
|
||||||
|
|
||||||
|
|
||||||
class BaseFormView(FormMixin, ProcessFormView):
|
class BaseFormView(FormMixin, ProcessFormView):
|
||||||
"""
|
"""A base view for displaying a form."""
|
||||||
A base view for displaying a form.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class FormView(TemplateResponseMixin, BaseFormView):
|
class FormView(TemplateResponseMixin, BaseFormView):
|
||||||
"""
|
"""A view for displaying a form and rendering a template response."""
|
||||||
A view for displaying a form, and rendering a template response.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class BaseCreateView(ModelFormMixin, ProcessFormView):
|
class BaseCreateView(ModelFormMixin, ProcessFormView):
|
||||||
|
@ -219,8 +179,7 @@ class BaseCreateView(ModelFormMixin, ProcessFormView):
|
||||||
|
|
||||||
class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView):
|
class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView):
|
||||||
"""
|
"""
|
||||||
View for creating a new object instance,
|
View for creating a new object, with a response rendered by a template.
|
||||||
with a response rendered by template.
|
|
||||||
"""
|
"""
|
||||||
template_name_suffix = '_form'
|
template_name_suffix = '_form'
|
||||||
|
|
||||||
|
@ -241,23 +200,18 @@ class BaseUpdateView(ModelFormMixin, ProcessFormView):
|
||||||
|
|
||||||
|
|
||||||
class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView):
|
class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView):
|
||||||
"""
|
"""View for updating an object, with a response rendered by a template."""
|
||||||
View for updating an object,
|
|
||||||
with a response rendered by template.
|
|
||||||
"""
|
|
||||||
template_name_suffix = '_form'
|
template_name_suffix = '_form'
|
||||||
|
|
||||||
|
|
||||||
class DeletionMixin:
|
class DeletionMixin:
|
||||||
"""
|
"""Provide the ability to delete objects."""
|
||||||
A mixin providing the ability to delete objects
|
|
||||||
"""
|
|
||||||
success_url = None
|
success_url = None
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Calls the delete() method on the fetched object and then
|
Call the delete() method on the fetched object and then redirect to the
|
||||||
redirects to the success URL.
|
success URL.
|
||||||
"""
|
"""
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
success_url = self.get_success_url()
|
success_url = self.get_success_url()
|
||||||
|
@ -286,7 +240,7 @@ class BaseDeleteView(DeletionMixin, BaseDetailView):
|
||||||
|
|
||||||
class DeleteView(SingleObjectTemplateResponseMixin, BaseDeleteView):
|
class DeleteView(SingleObjectTemplateResponseMixin, BaseDeleteView):
|
||||||
"""
|
"""
|
||||||
View for deleting an object retrieved with `self.get_object()`,
|
View for deleting an object retrieved with self.get_object(), with a
|
||||||
with a response rendered by template.
|
response rendered by a template.
|
||||||
"""
|
"""
|
||||||
template_name_suffix = '_confirm_delete'
|
template_name_suffix = '_confirm_delete'
|
||||||
|
|
|
@ -7,9 +7,7 @@ from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
|
||||||
|
|
||||||
|
|
||||||
class MultipleObjectMixin(ContextMixin):
|
class MultipleObjectMixin(ContextMixin):
|
||||||
"""
|
"""A mixin for views manipulating multiple objects."""
|
||||||
A mixin for views manipulating multiple objects.
|
|
||||||
"""
|
|
||||||
allow_empty = True
|
allow_empty = True
|
||||||
queryset = None
|
queryset = None
|
||||||
model = None
|
model = None
|
||||||
|
@ -50,15 +48,11 @@ class MultipleObjectMixin(ContextMixin):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_ordering(self):
|
def get_ordering(self):
|
||||||
"""
|
"""Return the field or fields to use for ordering the queryset."""
|
||||||
Return the field or fields to use for ordering the queryset.
|
|
||||||
"""
|
|
||||||
return self.ordering
|
return self.ordering
|
||||||
|
|
||||||
def paginate_queryset(self, queryset, page_size):
|
def paginate_queryset(self, queryset, page_size):
|
||||||
"""
|
"""Paginate the queryset, if needed."""
|
||||||
Paginate the queryset, if needed.
|
|
||||||
"""
|
|
||||||
paginator = self.get_paginator(
|
paginator = self.get_paginator(
|
||||||
queryset, page_size, orphans=self.get_paginate_orphans(),
|
queryset, page_size, orphans=self.get_paginate_orphans(),
|
||||||
allow_empty_first_page=self.get_allow_empty())
|
allow_empty_first_page=self.get_allow_empty())
|
||||||
|
@ -88,31 +82,27 @@ class MultipleObjectMixin(ContextMixin):
|
||||||
|
|
||||||
def get_paginator(self, queryset, per_page, orphans=0,
|
def get_paginator(self, queryset, per_page, orphans=0,
|
||||||
allow_empty_first_page=True, **kwargs):
|
allow_empty_first_page=True, **kwargs):
|
||||||
"""
|
"""Return an instance of the paginator for this view."""
|
||||||
Return an instance of the paginator for this view.
|
|
||||||
"""
|
|
||||||
return self.paginator_class(
|
return self.paginator_class(
|
||||||
queryset, per_page, orphans=orphans,
|
queryset, per_page, orphans=orphans,
|
||||||
allow_empty_first_page=allow_empty_first_page, **kwargs)
|
allow_empty_first_page=allow_empty_first_page, **kwargs)
|
||||||
|
|
||||||
def get_paginate_orphans(self):
|
def get_paginate_orphans(self):
|
||||||
"""
|
"""
|
||||||
Returns the maximum number of orphans extend the last page by when
|
Return the maximum number of orphans extend the last page by when
|
||||||
paginating.
|
paginating.
|
||||||
"""
|
"""
|
||||||
return self.paginate_orphans
|
return self.paginate_orphans
|
||||||
|
|
||||||
def get_allow_empty(self):
|
def get_allow_empty(self):
|
||||||
"""
|
"""
|
||||||
Returns ``True`` if the view should display empty lists, and ``False``
|
Return ``True`` if the view should display empty lists and ``False``
|
||||||
if a 404 should be raised instead.
|
if a 404 should be raised instead.
|
||||||
"""
|
"""
|
||||||
return self.allow_empty
|
return self.allow_empty
|
||||||
|
|
||||||
def get_context_object_name(self, object_list):
|
def get_context_object_name(self, object_list):
|
||||||
"""
|
"""Get the name of the item to be used in the context."""
|
||||||
Get the name of the item to be used in the context.
|
|
||||||
"""
|
|
||||||
if self.context_object_name:
|
if self.context_object_name:
|
||||||
return self.context_object_name
|
return self.context_object_name
|
||||||
elif hasattr(object_list, 'model'):
|
elif hasattr(object_list, 'model'):
|
||||||
|
@ -121,9 +111,7 @@ class MultipleObjectMixin(ContextMixin):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_context_data(self, *, object_list=None, **kwargs):
|
def get_context_data(self, *, object_list=None, **kwargs):
|
||||||
"""
|
"""Get the context for this view."""
|
||||||
Get the context for this view.
|
|
||||||
"""
|
|
||||||
queryset = object_list if object_list is not None else self.object_list
|
queryset = object_list if object_list is not None else self.object_list
|
||||||
page_size = self.get_paginate_by(queryset)
|
page_size = self.get_paginate_by(queryset)
|
||||||
context_object_name = self.get_context_object_name(queryset)
|
context_object_name = self.get_context_object_name(queryset)
|
||||||
|
@ -149,9 +137,7 @@ class MultipleObjectMixin(ContextMixin):
|
||||||
|
|
||||||
|
|
||||||
class BaseListView(MultipleObjectMixin, View):
|
class BaseListView(MultipleObjectMixin, View):
|
||||||
"""
|
"""A base view for displaying a list of objects."""
|
||||||
A base view for displaying a list of objects.
|
|
||||||
"""
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object_list = self.get_queryset()
|
self.object_list = self.get_queryset()
|
||||||
allow_empty = self.get_allow_empty()
|
allow_empty = self.get_allow_empty()
|
||||||
|
@ -173,9 +159,7 @@ class BaseListView(MultipleObjectMixin, View):
|
||||||
|
|
||||||
|
|
||||||
class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):
|
class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):
|
||||||
"""
|
"""Mixin for responding with a template and list of objects."""
|
||||||
Mixin for responding with a template and list of objects.
|
|
||||||
"""
|
|
||||||
template_name_suffix = '_list'
|
template_name_suffix = '_list'
|
||||||
|
|
||||||
def get_template_names(self):
|
def get_template_names(self):
|
||||||
|
|
|
@ -22,9 +22,9 @@ LANGUAGE_QUERY_PARAMETER = 'language'
|
||||||
|
|
||||||
def set_language(request):
|
def set_language(request):
|
||||||
"""
|
"""
|
||||||
Redirect to a given url while setting the chosen language in the
|
Redirect to a given URL while setting the chosen language in the session or
|
||||||
session or cookie. The url and the language code need to be
|
cookie. The URL and the language code need to be specified in the request
|
||||||
specified in the request parameters.
|
parameters.
|
||||||
|
|
||||||
Since this view changes how the user will see the rest of the site, it must
|
Since this view changes how the user will see the rest of the site, it must
|
||||||
only be accessed as a POST request. If called as a GET request, it will
|
only be accessed as a POST request. If called as a GET request, it will
|
||||||
|
@ -60,9 +60,7 @@ def set_language(request):
|
||||||
|
|
||||||
|
|
||||||
def get_formats():
|
def get_formats():
|
||||||
"""
|
"""Return all formats strings required for i18n to work."""
|
||||||
Returns all formats strings required for i18n to work
|
|
||||||
"""
|
|
||||||
FORMAT_SETTINGS = (
|
FORMAT_SETTINGS = (
|
||||||
'DATE_FORMAT', 'DATETIME_FORMAT', 'TIME_FORMAT',
|
'DATE_FORMAT', 'DATETIME_FORMAT', 'TIME_FORMAT',
|
||||||
'YEAR_MONTH_FORMAT', 'MONTH_DAY_FORMAT', 'SHORT_DATE_FORMAT',
|
'YEAR_MONTH_FORMAT', 'MONTH_DAY_FORMAT', 'SHORT_DATE_FORMAT',
|
||||||
|
@ -207,7 +205,7 @@ def render_javascript_catalog(catalog=None, plural=None):
|
||||||
|
|
||||||
def null_javascript_catalog(request, domain=None, packages=None):
|
def null_javascript_catalog(request, domain=None, packages=None):
|
||||||
"""
|
"""
|
||||||
Returns "identity" versions of the JavaScript i18n functions -- i.e.,
|
Return "identity" versions of the JavaScript i18n functions -- i.e.,
|
||||||
versions that don't actually do anything.
|
versions that don't actually do anything.
|
||||||
"""
|
"""
|
||||||
return render_javascript_catalog()
|
return render_javascript_catalog()
|
||||||
|
@ -217,7 +215,7 @@ class JavaScriptCatalog(View):
|
||||||
"""
|
"""
|
||||||
Return the selected language catalog as a JavaScript library.
|
Return the selected language catalog as a JavaScript library.
|
||||||
|
|
||||||
Receives the list of packages to check for translations in the `packages`
|
Receive the list of packages to check for translations in the `packages`
|
||||||
kwarg either from the extra dictionary passed to the url() function or as a
|
kwarg either from the extra dictionary passed to the url() function or as a
|
||||||
plus-sign delimited string from the request. Default is 'django.conf'.
|
plus-sign delimited string from the request. Default is 'django.conf'.
|
||||||
|
|
||||||
|
@ -305,7 +303,7 @@ class JSONCatalog(JavaScriptCatalog):
|
||||||
"""
|
"""
|
||||||
Return the selected language catalog as a JSON object.
|
Return the selected language catalog as a JSON object.
|
||||||
|
|
||||||
Receives the same parameters as JavaScriptCatalog and returns a response
|
Receive the same parameters as JavaScriptCatalog and return a response
|
||||||
with a JSON object of the following format:
|
with a JSON object of the following format:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue