views.py 12 KB

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