Класс DetailView (Django 3.0)
from django.views.generic import DetailView
Render a "detail" view of an object. By default this is a model instance looked up from `self.queryset`, but the view will support display of *any* object by overriding `self.get_object()`.
Предки (MRO)
Атрибуты
Определено в | |
---|---|
content_type = None
|
TemplateResponseMixin |
context_object_name = None
|
SingleObjectMixin |
extra_context = None
|
ContextMixin |
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
|
View |
model = None
|
SingleObjectMixin |
pk_url_kwarg = 'pk'
|
SingleObjectMixin |
query_pk_and_slug = False
|
SingleObjectMixin |
queryset = None
|
SingleObjectMixin |
response_class = <class 'django.template.response.TemplateResponse'>
|
TemplateResponseMixin |
slug_field = 'slug'
|
SingleObjectMixin |
slug_url_kwarg = 'slug'
|
SingleObjectMixin |
template_engine = None
|
TemplateResponseMixin |
template_name = None
|
TemplateResponseMixin |
template_name_field = None
|
SingleObjectTemplateResponseMixin |
template_name_suffix = '_detail'
|
SingleObjectTemplateResponseMixin |
Методы
def _allowed_methods(self):
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
Main entry point for a request-response process.
@classonlymethod
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
SingleObjectMixin
Insert the single object into the context dict.
def get_context_data(self, **kwargs):
"""Insert the single object into the context dict."""
context = {}
if self.object:
context['object'] = self.object
context_object_name = self.get_context_object_name(self.object)
if context_object_name:
context[context_object_name] = self.object
context.update(kwargs)
return super().get_context_data(**context)
ContextMixin
def get_context_data(self, **kwargs):
kwargs.setdefault('view', self)
if self.extra_context is not None:
kwargs.update(self.extra_context)
return kwargs
Get the name to use for the object.
def get_context_object_name(self, obj):
"""Get the name to use for the object."""
if self.context_object_name:
return self.context_object_name
elif isinstance(obj, models.Model):
return obj._meta.model_name
else:
return None
Return the object the view is displaying. Require `self.queryset` and a `pk` or `slug` argument in the URLconf. Subclasses can override this to return any object.
def get_object(self, queryset=None):
"""
Return the object the view is displaying.
Require `self.queryset` and a `pk` or `slug` argument in the URLconf.
Subclasses can override this to return any object.
"""
# Use a custom queryset if provided; this is required for subclasses
# like DateDetailView
if queryset is None:
queryset = self.get_queryset()
# Next, try looking up by primary key.
pk = self.kwargs.get(self.pk_url_kwarg)
slug = self.kwargs.get(self.slug_url_kwarg)
if pk is not None:
queryset = queryset.filter(pk=pk)
# Next, try looking up by slug.
if slug is not None and (pk is None or self.query_pk_and_slug):
slug_field = self.get_slug_field()
queryset = queryset.filter(**{slug_field: slug})
# If none of those are defined, it's an error.
if pk is None and slug is None:
raise AttributeError(
"Generic detail view %s must be called with either an object "
"pk or a slug in the URLconf." % self.__class__.__name__
)
try:
# Get the single item from the filtered queryset
obj = queryset.get()
except queryset.model.DoesNotExist:
raise Http404(_("No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
return obj
Return the `QuerySet` that will be used to look up the object. This method is called by the default implementation of get_object() and may not be called if get_object() is overridden.
def get_queryset(self):
"""
Return the `QuerySet` that will be used to look up the object.
This method is called by the default implementation of get_object() and
may not be called if get_object() is overridden.
"""
if self.queryset is None:
if self.model:
return self.model._default_manager.all()
else:
raise ImproperlyConfigured(
"%(cls)s is missing a QuerySet. Define "
"%(cls)s.model, %(cls)s.queryset, or override "
"%(cls)s.get_queryset()." % {
'cls': self.__class__.__name__
}
)
return self.queryset.all()
Get the name of a slug field to be used to look up by slug.
def get_slug_field(self):
"""Get the name of a slug field to be used to look up by slug."""
return self.slug_field
SingleObjectTemplateResponseMixin
Return a list of template names to be used for the request. May not be called if render_to_response() is overridden. Return the following list: * the value of ``template_name`` on the view (if provided) * the contents of the ``template_name_field`` field on the object instance that the view is operating upon (if available) * ``<app_label>/<model_name><template_name_suffix>.html``
def get_template_names(self):
"""
Return a list of template names to be used for the request. May not be
called if render_to_response() is overridden. Return the following list:
* the value of ``template_name`` on the view (if provided)
* the contents of the ``template_name_field`` field on the
object instance that the view is operating upon (if available)
* ``<app_label>/<model_name><template_name_suffix>.html``
"""
try:
names = super().get_template_names()
except ImproperlyConfigured:
# If template_name isn't specified, it's not a problem --
# we just start with an empty list.
names = []
# If self.template_name_field is set, grab the value of the field
# of that name from the object; this is the most specific template
# name, if given.
if self.object and self.template_name_field:
name = getattr(self.object, self.template_name_field, None)
if name:
names.insert(0, name)
# The least-specific option is the default <app>/<model>_detail.html;
# only use this if the object in question is a model.
if isinstance(self.object, models.Model):
object_meta = self.object._meta
names.append("%s/%s%s.html" % (
object_meta.app_label,
object_meta.model_name,
self.template_name_suffix
))
elif getattr(self, 'model', None) is not None and issubclass(self.model, models.Model):
names.append("%s/%s%s.html" % (
self.model._meta.app_label,
self.model._meta.model_name,
self.template_name_suffix
))
# If we still haven't managed to find any template names, we should
# re-raise the ImproperlyConfigured to alert the user.
if not names:
raise
return names
TemplateResponseMixin
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.
def get_template_names(self):
"""
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.
"""
if self.template_name is None:
raise ImproperlyConfigured(
"TemplateResponseMixin requires either a definition of "
"'template_name' or an implementation of 'get_template_names()'")
else:
return [self.template_name]
def http_method_not_allowed(self, request, *args, **kwargs):
logger.warning(
'Method Not Allowed (%s): %s', request.method, request.path,
extra={'status_code': 405, 'request': request}
)
return HttpResponseNotAllowed(self._allowed_methods())
Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things.
def __init__(self, **kwargs):
"""
Constructor. Called in the URLconf; can contain helpful extra
keyword arguments, and other things.
"""
# Go through keyword arguments, and either save their values to our
# instance, or raise an error.
for key, value in kwargs.items():
setattr(self, key, value)
Handle responding to requests for the OPTIONS HTTP verb.
def options(self, request, *args, **kwargs):
"""Handle responding to requests for the OPTIONS HTTP verb."""
response = HttpResponse()
response['Allow'] = ', '.join(self._allowed_methods())
response['Content-Length'] = '0'
return response
Return a response, using the `response_class` for this view, with a template rendered with the given context. Pass response_kwargs to the constructor of the response class.
def render_to_response(self, context, **response_kwargs):
"""
Return a response, using the `response_class` for this view, with a
template rendered with the given context.
Pass response_kwargs to the constructor of the response class.
"""
response_kwargs.setdefault('content_type', self.content_type)
return self.response_class(
request=self.request,
template=self.get_template_names(),
context=context,
using=self.template_engine,
**response_kwargs
)
Initialize attributes shared by all view methods.
def setup(self, request, *args, **kwargs):
"""Initialize attributes shared by all view methods."""
self.request = request
self.args = args
self.kwargs = kwargs