views.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. import json
  2. from urllib.parse import urlencode
  3. from xml.dom.minidom import parseString
  4. from django.contrib.auth.decorators import login_required, permission_required
  5. from django.core import mail
  6. from django.core.exceptions import ValidationError
  7. from django.forms import fields
  8. from django.forms.forms import Form
  9. from django.forms.formsets import BaseFormSet, formset_factory
  10. from django.http import (
  11. HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed,
  12. HttpResponseNotFound, HttpResponseRedirect,
  13. )
  14. from django.shortcuts import render
  15. from django.template import Context, Template
  16. from django.test import Client
  17. from django.utils.decorators import method_decorator
  18. def get_view(request):
  19. "A simple view that expects a GET request, and returns a rendered template"
  20. t = Template('This is a test. {{ var }} is the value.', name='GET Template')
  21. c = Context({'var': request.GET.get('var', 42)})
  22. return HttpResponse(t.render(c))
  23. async def async_get_view(request):
  24. return HttpResponse(b'GET content.')
  25. def trace_view(request):
  26. """
  27. A simple view that expects a TRACE request and echoes its status line.
  28. TRACE requests should not have an entity; the view will return a 400 status
  29. response if it is present.
  30. """
  31. if request.method.upper() != "TRACE":
  32. return HttpResponseNotAllowed("TRACE")
  33. elif request.body:
  34. return HttpResponseBadRequest("TRACE requests MUST NOT include an entity")
  35. else:
  36. protocol = request.META["SERVER_PROTOCOL"]
  37. t = Template(
  38. '{{ method }} {{ uri }} {{ version }}',
  39. name="TRACE Template",
  40. )
  41. c = Context({
  42. 'method': request.method,
  43. 'uri': request.path,
  44. 'version': protocol,
  45. })
  46. return HttpResponse(t.render(c))
  47. def put_view(request):
  48. if request.method == 'PUT':
  49. t = Template('Data received: {{ data }} is the body.', name='PUT Template')
  50. c = Context({
  51. 'Content-Length': request.META['CONTENT_LENGTH'],
  52. 'data': request.body.decode(),
  53. })
  54. else:
  55. t = Template('Viewing GET page.', name='Empty GET Template')
  56. c = Context()
  57. return HttpResponse(t.render(c))
  58. def post_view(request):
  59. """A view that expects a POST, and returns a different template depending
  60. on whether any POST data is available
  61. """
  62. if request.method == 'POST':
  63. if request.POST:
  64. t = Template('Data received: {{ data }} is the value.', name='POST Template')
  65. c = Context({'data': request.POST['value']})
  66. else:
  67. t = Template('Viewing POST page.', name='Empty POST Template')
  68. c = Context()
  69. else:
  70. t = Template('Viewing GET page.', name='Empty GET Template')
  71. c = Context()
  72. return HttpResponse(t.render(c))
  73. def json_view(request):
  74. """
  75. A view that expects a request with the header 'application/json' and JSON
  76. data, which is deserialized and included in the context.
  77. """
  78. if request.META.get('CONTENT_TYPE') != 'application/json':
  79. return HttpResponse()
  80. t = Template('Viewing {} page. With data {{ data }}.'.format(request.method))
  81. data = json.loads(request.body.decode('utf-8'))
  82. c = Context({'data': data})
  83. return HttpResponse(t.render(c))
  84. def view_with_header(request):
  85. "A view that has a custom header"
  86. response = HttpResponse()
  87. response.headers['X-DJANGO-TEST'] = 'Slartibartfast'
  88. return response
  89. def raw_post_view(request):
  90. """A view which expects raw XML to be posted and returns content extracted
  91. from the XML"""
  92. if request.method == 'POST':
  93. root = parseString(request.body)
  94. first_book = root.firstChild.firstChild
  95. title, author = [n.firstChild.nodeValue for n in first_book.childNodes]
  96. t = Template("{{ title }} - {{ author }}", name="Book template")
  97. c = Context({"title": title, "author": author})
  98. else:
  99. t = Template("GET request.", name="Book GET template")
  100. c = Context()
  101. return HttpResponse(t.render(c))
  102. def redirect_view(request):
  103. "A view that redirects all requests to the GET view"
  104. if request.GET:
  105. query = '?' + urlencode(request.GET, True)
  106. else:
  107. query = ''
  108. return HttpResponseRedirect('/get_view/' + query)
  109. def method_saving_307_redirect_query_string_view(request):
  110. return HttpResponseRedirect('/post_view/?hello=world', status=307)
  111. def method_saving_308_redirect_query_string_view(request):
  112. return HttpResponseRedirect('/post_view/?hello=world', status=308)
  113. def _post_view_redirect(request, status_code):
  114. """Redirect to /post_view/ using the status code."""
  115. redirect_to = request.GET.get('to', '/post_view/')
  116. return HttpResponseRedirect(redirect_to, status=status_code)
  117. def method_saving_307_redirect_view(request):
  118. return _post_view_redirect(request, 307)
  119. def method_saving_308_redirect_view(request):
  120. return _post_view_redirect(request, 308)
  121. def view_with_secure(request):
  122. "A view that indicates if the request was secure"
  123. response = HttpResponse()
  124. response.test_was_secure_request = request.is_secure()
  125. response.test_server_port = request.META.get('SERVER_PORT', 80)
  126. return response
  127. def double_redirect_view(request):
  128. "A view that redirects all requests to a redirection view"
  129. return HttpResponseRedirect('/permanent_redirect_view/')
  130. def bad_view(request):
  131. "A view that returns a 404 with some error content"
  132. return HttpResponseNotFound('Not found!. This page contains some MAGIC content')
  133. TestChoices = (
  134. ('a', 'First Choice'),
  135. ('b', 'Second Choice'),
  136. ('c', 'Third Choice'),
  137. ('d', 'Fourth Choice'),
  138. ('e', 'Fifth Choice')
  139. )
  140. class TestForm(Form):
  141. text = fields.CharField()
  142. email = fields.EmailField()
  143. value = fields.IntegerField()
  144. single = fields.ChoiceField(choices=TestChoices)
  145. multi = fields.MultipleChoiceField(choices=TestChoices)
  146. def clean(self):
  147. cleaned_data = self.cleaned_data
  148. if cleaned_data.get("text") == "Raise non-field error":
  149. raise ValidationError("Non-field error.")
  150. return cleaned_data
  151. def form_view(request):
  152. "A view that tests a simple form"
  153. if request.method == 'POST':
  154. form = TestForm(request.POST)
  155. if form.is_valid():
  156. t = Template('Valid POST data.', name='Valid POST Template')
  157. c = Context()
  158. else:
  159. t = Template('Invalid POST data. {{ form.errors }}', name='Invalid POST Template')
  160. c = Context({'form': form})
  161. else:
  162. form = TestForm(request.GET)
  163. t = Template('Viewing base form. {{ form }}.', name='Form GET Template')
  164. c = Context({'form': form})
  165. return HttpResponse(t.render(c))
  166. def form_view_with_template(request):
  167. "A view that tests a simple form"
  168. if request.method == 'POST':
  169. form = TestForm(request.POST)
  170. if form.is_valid():
  171. message = 'POST data OK'
  172. else:
  173. message = 'POST data has errors'
  174. else:
  175. form = TestForm()
  176. message = 'GET form page'
  177. return render(request, 'form_view.html', {
  178. 'form': form,
  179. 'message': message,
  180. })
  181. class BaseTestFormSet(BaseFormSet):
  182. def clean(self):
  183. """No two email addresses are the same."""
  184. if any(self.errors):
  185. # Don't bother validating the formset unless each form is valid
  186. return
  187. emails = []
  188. for i in range(0, self.total_form_count()):
  189. form = self.forms[i]
  190. email = form.cleaned_data['email']
  191. if email in emails:
  192. raise ValidationError(
  193. "Forms in a set must have distinct email addresses."
  194. )
  195. emails.append(email)
  196. TestFormSet = formset_factory(TestForm, BaseTestFormSet)
  197. def formset_view(request):
  198. "A view that tests a simple formset"
  199. if request.method == 'POST':
  200. formset = TestFormSet(request.POST)
  201. if formset.is_valid():
  202. t = Template('Valid POST data.', name='Valid POST Template')
  203. c = Context()
  204. else:
  205. t = Template('Invalid POST data. {{ my_formset.errors }}',
  206. name='Invalid POST Template')
  207. c = Context({'my_formset': formset})
  208. else:
  209. formset = TestForm(request.GET)
  210. t = Template('Viewing base formset. {{ my_formset }}.',
  211. name='Formset GET Template')
  212. c = Context({'my_formset': formset})
  213. return HttpResponse(t.render(c))
  214. @login_required
  215. def login_protected_view(request):
  216. "A simple view that is login protected."
  217. t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template')
  218. c = Context({'user': request.user})
  219. return HttpResponse(t.render(c))
  220. @login_required(redirect_field_name='redirect_to')
  221. def login_protected_view_changed_redirect(request):
  222. "A simple view that is login protected with a custom redirect field set"
  223. t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template')
  224. c = Context({'user': request.user})
  225. return HttpResponse(t.render(c))
  226. def _permission_protected_view(request):
  227. "A simple view that is permission protected."
  228. t = Template('This is a permission protected test. '
  229. 'Username is {{ user.username }}. '
  230. 'Permissions are {{ user.get_all_permissions }}.',
  231. name='Permissions Template')
  232. c = Context({'user': request.user})
  233. return HttpResponse(t.render(c))
  234. permission_protected_view = permission_required('permission_not_granted')(_permission_protected_view)
  235. permission_protected_view_exception = (
  236. permission_required('permission_not_granted', raise_exception=True)(_permission_protected_view)
  237. )
  238. class _ViewManager:
  239. @method_decorator(login_required)
  240. def login_protected_view(self, request):
  241. t = Template('This is a login protected test using a method. '
  242. 'Username is {{ user.username }}.',
  243. name='Login Method Template')
  244. c = Context({'user': request.user})
  245. return HttpResponse(t.render(c))
  246. @method_decorator(permission_required('permission_not_granted'))
  247. def permission_protected_view(self, request):
  248. t = Template('This is a permission protected test using a method. '
  249. 'Username is {{ user.username }}. '
  250. 'Permissions are {{ user.get_all_permissions }}.',
  251. name='Permissions Template')
  252. c = Context({'user': request.user})
  253. return HttpResponse(t.render(c))
  254. _view_manager = _ViewManager()
  255. login_protected_method_view = _view_manager.login_protected_view
  256. permission_protected_method_view = _view_manager.permission_protected_view
  257. def session_view(request):
  258. "A view that modifies the session"
  259. request.session['tobacconist'] = 'hovercraft'
  260. t = Template('This is a view that modifies the session.',
  261. name='Session Modifying View Template')
  262. c = Context()
  263. return HttpResponse(t.render(c))
  264. def broken_view(request):
  265. """A view which just raises an exception, simulating a broken view."""
  266. raise KeyError("Oops! Looks like you wrote some bad code.")
  267. def mail_sending_view(request):
  268. mail.EmailMessage(
  269. "Test message",
  270. "This is a test email",
  271. "from@example.com",
  272. ['first@example.com', 'second@example.com']).send()
  273. return HttpResponse("Mail sent")
  274. def mass_mail_sending_view(request):
  275. m1 = mail.EmailMessage(
  276. 'First Test message',
  277. 'This is the first test email',
  278. 'from@example.com',
  279. ['first@example.com', 'second@example.com'])
  280. m2 = mail.EmailMessage(
  281. 'Second Test message',
  282. 'This is the second test email',
  283. 'from@example.com',
  284. ['second@example.com', 'third@example.com'])
  285. c = mail.get_connection()
  286. c.send_messages([m1, m2])
  287. return HttpResponse("Mail sent")
  288. def nesting_exception_view(request):
  289. """
  290. A view that uses a nested client to call another view and then raises an
  291. exception.
  292. """
  293. client = Client()
  294. client.get('/get_view/')
  295. raise Exception('exception message')
  296. def django_project_redirect(request):
  297. return HttpResponseRedirect('https://www.djangoproject.com/')
  298. def upload_view(request):
  299. """Prints keys of request.FILES to the response."""
  300. return HttpResponse(', '.join(request.FILES))
  301. class TwoArgException(Exception):
  302. def __init__(self, one, two):
  303. pass
  304. def two_arg_exception(request):
  305. raise TwoArgException('one', 'two')