views.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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['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 _post_view_redirect(request, status_code):
  110. """Redirect to /post_view/ using the status code."""
  111. redirect_to = request.GET.get('to', '/post_view/')
  112. return HttpResponseRedirect(redirect_to, status=status_code)
  113. def method_saving_307_redirect_view(request):
  114. return _post_view_redirect(request, 307)
  115. def method_saving_308_redirect_view(request):
  116. return _post_view_redirect(request, 308)
  117. def view_with_secure(request):
  118. "A view that indicates if the request was secure"
  119. response = HttpResponse()
  120. response.test_was_secure_request = request.is_secure()
  121. response.test_server_port = request.META.get('SERVER_PORT', 80)
  122. return response
  123. def double_redirect_view(request):
  124. "A view that redirects all requests to a redirection view"
  125. return HttpResponseRedirect('/permanent_redirect_view/')
  126. def bad_view(request):
  127. "A view that returns a 404 with some error content"
  128. return HttpResponseNotFound('Not found!. This page contains some MAGIC content')
  129. TestChoices = (
  130. ('a', 'First Choice'),
  131. ('b', 'Second Choice'),
  132. ('c', 'Third Choice'),
  133. ('d', 'Fourth Choice'),
  134. ('e', 'Fifth Choice')
  135. )
  136. class TestForm(Form):
  137. text = fields.CharField()
  138. email = fields.EmailField()
  139. value = fields.IntegerField()
  140. single = fields.ChoiceField(choices=TestChoices)
  141. multi = fields.MultipleChoiceField(choices=TestChoices)
  142. def clean(self):
  143. cleaned_data = self.cleaned_data
  144. if cleaned_data.get("text") == "Raise non-field error":
  145. raise ValidationError("Non-field error.")
  146. return cleaned_data
  147. def form_view(request):
  148. "A view that tests a simple form"
  149. if request.method == 'POST':
  150. form = TestForm(request.POST)
  151. if form.is_valid():
  152. t = Template('Valid POST data.', name='Valid POST Template')
  153. c = Context()
  154. else:
  155. t = Template('Invalid POST data. {{ form.errors }}', name='Invalid POST Template')
  156. c = Context({'form': form})
  157. else:
  158. form = TestForm(request.GET)
  159. t = Template('Viewing base form. {{ form }}.', name='Form GET Template')
  160. c = Context({'form': form})
  161. return HttpResponse(t.render(c))
  162. def form_view_with_template(request):
  163. "A view that tests a simple form"
  164. if request.method == 'POST':
  165. form = TestForm(request.POST)
  166. if form.is_valid():
  167. message = 'POST data OK'
  168. else:
  169. message = 'POST data has errors'
  170. else:
  171. form = TestForm()
  172. message = 'GET form page'
  173. return render(request, 'form_view.html', {
  174. 'form': form,
  175. 'message': message,
  176. })
  177. class BaseTestFormSet(BaseFormSet):
  178. def clean(self):
  179. """No two email addresses are the same."""
  180. if any(self.errors):
  181. # Don't bother validating the formset unless each form is valid
  182. return
  183. emails = []
  184. for i in range(0, self.total_form_count()):
  185. form = self.forms[i]
  186. email = form.cleaned_data['email']
  187. if email in emails:
  188. raise ValidationError(
  189. "Forms in a set must have distinct email addresses."
  190. )
  191. emails.append(email)
  192. TestFormSet = formset_factory(TestForm, BaseTestFormSet)
  193. def formset_view(request):
  194. "A view that tests a simple formset"
  195. if request.method == 'POST':
  196. formset = TestFormSet(request.POST)
  197. if formset.is_valid():
  198. t = Template('Valid POST data.', name='Valid POST Template')
  199. c = Context()
  200. else:
  201. t = Template('Invalid POST data. {{ my_formset.errors }}',
  202. name='Invalid POST Template')
  203. c = Context({'my_formset': formset})
  204. else:
  205. formset = TestForm(request.GET)
  206. t = Template('Viewing base formset. {{ my_formset }}.',
  207. name='Formset GET Template')
  208. c = Context({'my_formset': formset})
  209. return HttpResponse(t.render(c))
  210. @login_required
  211. def login_protected_view(request):
  212. "A simple view that is login protected."
  213. t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template')
  214. c = Context({'user': request.user})
  215. return HttpResponse(t.render(c))
  216. @login_required(redirect_field_name='redirect_to')
  217. def login_protected_view_changed_redirect(request):
  218. "A simple view that is login protected with a custom redirect field set"
  219. t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template')
  220. c = Context({'user': request.user})
  221. return HttpResponse(t.render(c))
  222. def _permission_protected_view(request):
  223. "A simple view that is permission protected."
  224. t = Template('This is a permission protected test. '
  225. 'Username is {{ user.username }}. '
  226. 'Permissions are {{ user.get_all_permissions }}.',
  227. name='Permissions Template')
  228. c = Context({'user': request.user})
  229. return HttpResponse(t.render(c))
  230. permission_protected_view = permission_required('permission_not_granted')(_permission_protected_view)
  231. permission_protected_view_exception = (
  232. permission_required('permission_not_granted', raise_exception=True)(_permission_protected_view)
  233. )
  234. class _ViewManager:
  235. @method_decorator(login_required)
  236. def login_protected_view(self, request):
  237. t = Template('This is a login protected test using a method. '
  238. 'Username is {{ user.username }}.',
  239. name='Login Method Template')
  240. c = Context({'user': request.user})
  241. return HttpResponse(t.render(c))
  242. @method_decorator(permission_required('permission_not_granted'))
  243. def permission_protected_view(self, request):
  244. t = Template('This is a permission protected test using a method. '
  245. 'Username is {{ user.username }}. '
  246. 'Permissions are {{ user.get_all_permissions }}.',
  247. name='Permissions Template')
  248. c = Context({'user': request.user})
  249. return HttpResponse(t.render(c))
  250. _view_manager = _ViewManager()
  251. login_protected_method_view = _view_manager.login_protected_view
  252. permission_protected_method_view = _view_manager.permission_protected_view
  253. def session_view(request):
  254. "A view that modifies the session"
  255. request.session['tobacconist'] = 'hovercraft'
  256. t = Template('This is a view that modifies the session.',
  257. name='Session Modifying View Template')
  258. c = Context()
  259. return HttpResponse(t.render(c))
  260. def broken_view(request):
  261. """A view which just raises an exception, simulating a broken view."""
  262. raise KeyError("Oops! Looks like you wrote some bad code.")
  263. def mail_sending_view(request):
  264. mail.EmailMessage(
  265. "Test message",
  266. "This is a test email",
  267. "from@example.com",
  268. ['first@example.com', 'second@example.com']).send()
  269. return HttpResponse("Mail sent")
  270. def mass_mail_sending_view(request):
  271. m1 = mail.EmailMessage(
  272. 'First Test message',
  273. 'This is the first test email',
  274. 'from@example.com',
  275. ['first@example.com', 'second@example.com'])
  276. m2 = mail.EmailMessage(
  277. 'Second Test message',
  278. 'This is the second test email',
  279. 'from@example.com',
  280. ['second@example.com', 'third@example.com'])
  281. c = mail.get_connection()
  282. c.send_messages([m1, m2])
  283. return HttpResponse("Mail sent")
  284. def nesting_exception_view(request):
  285. """
  286. A view that uses a nested client to call another view and then raises an
  287. exception.
  288. """
  289. client = Client()
  290. client.get('/get_view/')
  291. raise Exception('exception message')
  292. def django_project_redirect(request):
  293. return HttpResponseRedirect('https://www.djangoproject.com/')
  294. def upload_view(request):
  295. """Prints keys of request.FILES to the response."""
  296. return HttpResponse(', '.join(request.FILES))
  297. class TwoArgException(Exception):
  298. def __init__(self, one, two):
  299. pass
  300. def two_arg_exception(request):
  301. raise TwoArgException('one', 'two')