Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

detail.py 6.5KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. from django.core.exceptions import ImproperlyConfigured
  2. from django.db import models
  3. from django.http import Http404
  4. from django.utils.translation import gettext as _
  5. from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
  6. class SingleObjectMixin(ContextMixin):
  7. """
  8. Provide the ability to retrieve a single object for further manipulation.
  9. """
  10. model = None
  11. queryset = None
  12. slug_field = "slug"
  13. context_object_name = None
  14. slug_url_kwarg = "slug"
  15. pk_url_kwarg = "pk"
  16. query_pk_and_slug = False
  17. def get_object(self, queryset=None):
  18. """
  19. Return the object the view is displaying.
  20. Require `self.queryset` and a `pk` or `slug` argument in the URLconf.
  21. Subclasses can override this to return any object.
  22. """
  23. # Use a custom queryset if provided; this is required for subclasses
  24. # like DateDetailView
  25. if queryset is None:
  26. queryset = self.get_queryset()
  27. # Next, try looking up by primary key.
  28. pk = self.kwargs.get(self.pk_url_kwarg)
  29. slug = self.kwargs.get(self.slug_url_kwarg)
  30. if pk is not None:
  31. queryset = queryset.filter(pk=pk)
  32. # Next, try looking up by slug.
  33. if slug is not None and (pk is None or self.query_pk_and_slug):
  34. slug_field = self.get_slug_field()
  35. queryset = queryset.filter(**{slug_field: slug})
  36. # If none of those are defined, it's an error.
  37. if pk is None and slug is None:
  38. raise AttributeError(
  39. "Generic detail view %s must be called with either an object "
  40. "pk or a slug in the URLconf." % self.__class__.__name__
  41. )
  42. try:
  43. # Get the single item from the filtered queryset
  44. obj = queryset.get()
  45. except queryset.model.DoesNotExist:
  46. raise Http404(
  47. _("No %(verbose_name)s found matching the query")
  48. % {"verbose_name": queryset.model._meta.verbose_name}
  49. )
  50. return obj
  51. def get_queryset(self):
  52. """
  53. Return the `QuerySet` that will be used to look up the object.
  54. This method is called by the default implementation of get_object() and
  55. may not be called if get_object() is overridden.
  56. """
  57. if self.queryset is None:
  58. if self.model:
  59. return self.model._default_manager.all()
  60. else:
  61. raise ImproperlyConfigured(
  62. "%(cls)s is missing a QuerySet. Define "
  63. "%(cls)s.model, %(cls)s.queryset, or override "
  64. "%(cls)s.get_queryset()." % {"cls": self.__class__.__name__}
  65. )
  66. return self.queryset.all()
  67. def get_slug_field(self):
  68. """Get the name of a slug field to be used to look up by slug."""
  69. return self.slug_field
  70. def get_context_object_name(self, obj):
  71. """Get the name to use for the object."""
  72. if self.context_object_name:
  73. return self.context_object_name
  74. elif isinstance(obj, models.Model):
  75. return obj._meta.model_name
  76. else:
  77. return None
  78. def get_context_data(self, **kwargs):
  79. """Insert the single object into the context dict."""
  80. context = {}
  81. if self.object:
  82. context["object"] = self.object
  83. context_object_name = self.get_context_object_name(self.object)
  84. if context_object_name:
  85. context[context_object_name] = self.object
  86. context.update(kwargs)
  87. return super().get_context_data(**context)
  88. class BaseDetailView(SingleObjectMixin, View):
  89. """A base view for displaying a single object."""
  90. def get(self, request, *args, **kwargs):
  91. self.object = self.get_object()
  92. context = self.get_context_data(object=self.object)
  93. return self.render_to_response(context)
  94. class SingleObjectTemplateResponseMixin(TemplateResponseMixin):
  95. template_name_field = None
  96. template_name_suffix = "_detail"
  97. def get_template_names(self):
  98. """
  99. Return a list of template names to be used for the request. May not be
  100. called if render_to_response() is overridden. Return the following list:
  101. * the value of ``template_name`` on the view (if provided)
  102. * the contents of the ``template_name_field`` field on the
  103. object instance that the view is operating upon (if available)
  104. * ``<app_label>/<model_name><template_name_suffix>.html``
  105. """
  106. try:
  107. names = super().get_template_names()
  108. except ImproperlyConfigured:
  109. # If template_name isn't specified, it's not a problem --
  110. # we just start with an empty list.
  111. names = []
  112. # If self.template_name_field is set, grab the value of the field
  113. # of that name from the object; this is the most specific template
  114. # name, if given.
  115. if self.object and self.template_name_field:
  116. name = getattr(self.object, self.template_name_field, None)
  117. if name:
  118. names.insert(0, name)
  119. # The least-specific option is the default <app>/<model>_detail.html;
  120. # only use this if the object in question is a model.
  121. if isinstance(self.object, models.Model):
  122. object_meta = self.object._meta
  123. names.append(
  124. "%s/%s%s.html"
  125. % (
  126. object_meta.app_label,
  127. object_meta.model_name,
  128. self.template_name_suffix,
  129. )
  130. )
  131. elif getattr(self, "model", None) is not None and issubclass(
  132. self.model, models.Model
  133. ):
  134. names.append(
  135. "%s/%s%s.html"
  136. % (
  137. self.model._meta.app_label,
  138. self.model._meta.model_name,
  139. self.template_name_suffix,
  140. )
  141. )
  142. # If we still haven't managed to find any template names, we should
  143. # re-raise the ImproperlyConfigured to alert the user.
  144. if not names:
  145. raise
  146. return names
  147. class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView):
  148. """
  149. Render a "detail" view of an object.
  150. By default this is a model instance looked up from `self.queryset`, but the
  151. view will support display of *any* object by overriding `self.get_object()`.
  152. """