import json from urllib.parse import urlencode from xml.dom.minidom import parseString from django.contrib.auth.decorators import login_required, permission_required from django.core import mail from django.core.exceptions import ValidationError from django.forms import fields from django.forms.forms import Form from django.forms.formsets import BaseFormSet, formset_factory from django.http import ( HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed, HttpResponseNotFound, HttpResponseRedirect, ) from django.shortcuts import render from django.template import Context, Template from django.test import Client from django.utils.decorators import method_decorator def get_view(request): "A simple view that expects a GET request, and returns a rendered template" t = Template("This is a test. {{ var }} is the value.", name="GET Template") c = Context({"var": request.GET.get("var", 42)}) return HttpResponse(t.render(c)) async def async_get_view(request): return HttpResponse(b"GET content.") def trace_view(request): """ A simple view that expects a TRACE request and echoes its status line. TRACE requests should not have an entity; the view will return a 400 status response if it is present. """ if request.method.upper() != "TRACE": return HttpResponseNotAllowed("TRACE") elif request.body: return HttpResponseBadRequest("TRACE requests MUST NOT include an entity") else: protocol = request.META["SERVER_PROTOCOL"] t = Template( "{{ method }} {{ uri }} {{ version }}", name="TRACE Template", ) c = Context( { "method": request.method, "uri": request.path, "version": protocol, } ) return HttpResponse(t.render(c)) def put_view(request): if request.method == "PUT": t = Template("Data received: {{ data }} is the body.", name="PUT Template") c = Context( { "Content-Length": request.META["CONTENT_LENGTH"], "data": request.body.decode(), } ) else: t = Template("Viewing GET page.", name="Empty GET Template") c = Context() return HttpResponse(t.render(c)) def post_view(request): """A view that expects a POST, and returns a different template depending on whether any POST data is available """ if request.method == "POST": if request.POST: t = Template( "Data received: {{ data }} is the value.", name="POST Template" ) c = Context({"data": request.POST["value"]}) else: t = Template("Viewing POST page.", name="Empty POST Template") c = Context() else: t = Template("Viewing GET page.", name="Empty GET Template") c = Context() return HttpResponse(t.render(c)) def post_then_get_view(request): """ A view that expects a POST request, returns a redirect response to itself providing only a ?success=true querystring, the value of this querystring is then rendered upon GET. """ if request.method == "POST": return HttpResponseRedirect("?success=true") t = Template("The value of success is {{ value }}.", name="GET Template") c = Context({"value": request.GET.get("success", "false")}) return HttpResponse(t.render(c)) def json_view(request): """ A view that expects a request with the header 'application/json' and JSON data, which is deserialized and included in the context. """ if request.META.get("CONTENT_TYPE") != "application/json": return HttpResponse() t = Template("Viewing {} page. With data {{ data }}.".format(request.method)) data = json.loads(request.body.decode("utf-8")) c = Context({"data": data}) return HttpResponse(t.render(c)) def view_with_header(request): "A view that has a custom header" response = HttpResponse() response.headers["X-DJANGO-TEST"] = "Slartibartfast" return response def raw_post_view(request): """A view which expects raw XML to be posted and returns content extracted from the XML""" if request.method == "POST": root = parseString(request.body) first_book = root.firstChild.firstChild title, author = [n.firstChild.nodeValue for n in first_book.childNodes] t = Template("{{ title }} - {{ author }}", name="Book template") c = Context({"title": title, "author": author}) else: t = Template("GET request.", name="Book GET template") c = Context() return HttpResponse(t.render(c)) def redirect_view(request): "A view that redirects all requests to the GET view" if request.GET: query = "?" + urlencode(request.GET, True) else: query = "" return HttpResponseRedirect("/get_view/" + query) def method_saving_307_redirect_query_string_view(request): return HttpResponseRedirect("/post_view/?hello=world", status=307) def method_saving_308_redirect_query_string_view(request): return HttpResponseRedirect("/post_view/?hello=world", status=308) def _post_view_redirect(request, status_code): """Redirect to /post_view/ using the status code.""" redirect_to = request.GET.get("to", "/post_view/") return HttpResponseRedirect(redirect_to, status=status_code) def method_saving_307_redirect_view(request): return _post_view_redirect(request, 307) def method_saving_308_redirect_view(request): return _post_view_redirect(request, 308) def view_with_secure(request): "A view that indicates if the request was secure" response = HttpResponse() response.test_was_secure_request = request.is_secure() response.test_server_port = request.META.get("SERVER_PORT", 80) return response def double_redirect_view(request): "A view that redirects all requests to a redirection view" return HttpResponseRedirect("/permanent_redirect_view/") def bad_view(request): "A view that returns a 404 with some error content" return HttpResponseNotFound("Not found!. This page contains some MAGIC content") TestChoices = ( ("a", "First Choice"), ("b", "Second Choice"), ("c", "Third Choice"), ("d", "Fourth Choice"), ("e", "Fifth Choice"), ) class TestForm(Form): text = fields.CharField() email = fields.EmailField() value = fields.IntegerField() single = fields.ChoiceField(choices=TestChoices) multi = fields.MultipleChoiceField(choices=TestChoices) def clean(self): cleaned_data = self.cleaned_data if cleaned_data.get("text") == "Raise non-field error": raise ValidationError("Non-field error.") return cleaned_data def form_view(request): "A view that tests a simple form" if request.method == "POST": form = TestForm(request.POST) if form.is_valid(): t = Template("Valid POST data.", name="Valid POST Template") c = Context() else: t = Template( "Invalid POST data. {{ form.errors }}", name="Invalid POST Template" ) c = Context({"form": form}) else: form = TestForm(request.GET) t = Template("Viewing base form. {{ form }}.", name="Form GET Template") c = Context({"form": form}) return HttpResponse(t.render(c)) def form_view_with_template(request): "A view that tests a simple form" if request.method == "POST": form = TestForm(request.POST) if form.is_valid(): message = "POST data OK" else: message = "POST data has errors" else: form = TestForm() message = "GET form page" return render( request, "form_view.html", { "form": form, "message": message, }, ) class BaseTestFormSet(BaseFormSet): def clean(self): """No two email addresses are the same.""" if any(self.errors): # Don't bother validating the formset unless each form is valid return emails = [] for form in self.forms: email = form.cleaned_data["email"] if email in emails: raise ValidationError( "Forms in a set must have distinct email addresses." ) emails.append(email) TestFormSet = formset_factory(TestForm, BaseTestFormSet) def formset_view(request): "A view that tests a simple formset" if request.method == "POST": formset = TestFormSet(request.POST) if formset.is_valid(): t = Template("Valid POST data.", name="Valid POST Template") c = Context() else: t = Template( "Invalid POST data. {{ my_formset.errors }}", name="Invalid POST Template", ) c = Context({"my_formset": formset}) else: formset = TestForm(request.GET) t = Template( "Viewing base formset. {{ my_formset }}.", name="Formset GET Template" ) c = Context({"my_formset": formset}) return HttpResponse(t.render(c)) @login_required def login_protected_view(request): "A simple view that is login protected." t = Template( "This is a login protected test. Username is {{ user.username }}.", name="Login Template", ) c = Context({"user": request.user}) return HttpResponse(t.render(c)) @login_required(redirect_field_name="redirect_to") def login_protected_view_changed_redirect(request): "A simple view that is login protected with a custom redirect field set" t = Template( "This is a login protected test. Username is {{ user.username }}.", name="Login Template", ) c = Context({"user": request.user}) return HttpResponse(t.render(c)) def _permission_protected_view(request): "A simple view that is permission protected." t = Template( "This is a permission protected test. " "Username is {{ user.username }}. " "Permissions are {{ user.get_all_permissions }}.", name="Permissions Template", ) c = Context({"user": request.user}) return HttpResponse(t.render(c)) permission_protected_view = permission_required("permission_not_granted")( _permission_protected_view ) permission_protected_view_exception = permission_required( "permission_not_granted", raise_exception=True )(_permission_protected_view) class _ViewManager: @method_decorator(login_required) def login_protected_view(self, request): t = Template( "This is a login protected test using a method. " "Username is {{ user.username }}.", name="Login Method Template", ) c = Context({"user": request.user}) return HttpResponse(t.render(c)) @method_decorator(permission_required("permission_not_granted")) def permission_protected_view(self, request): t = Template( "This is a permission protected test using a method. " "Username is {{ user.username }}. " "Permissions are {{ user.get_all_permissions }}.", name="Permissions Template", ) c = Context({"user": request.user}) return HttpResponse(t.render(c)) _view_manager = _ViewManager() login_protected_method_view = _view_manager.login_protected_view permission_protected_method_view = _view_manager.permission_protected_view def session_view(request): "A view that modifies the session" request.session["tobacconist"] = "hovercraft" t = Template( "This is a view that modifies the session.", name="Session Modifying View Template", ) c = Context() return HttpResponse(t.render(c)) def broken_view(request): """A view which just raises an exception, simulating a broken view.""" raise KeyError("Oops! Looks like you wrote some bad code.") def mail_sending_view(request): mail.EmailMessage( "Test message", "This is a test email", "from@example.com", ["first@example.com", "second@example.com"], ).send() return HttpResponse("Mail sent") def mass_mail_sending_view(request): m1 = mail.EmailMessage( "First Test message", "This is the first test email", "from@example.com", ["first@example.com", "second@example.com"], ) m2 = mail.EmailMessage( "Second Test message", "This is the second test email", "from@example.com", ["second@example.com", "third@example.com"], ) c = mail.get_connection() c.send_messages([m1, m2]) return HttpResponse("Mail sent") def nesting_exception_view(request): """ A view that uses a nested client to call another view and then raises an exception. """ client = Client() client.get("/get_view/") raise Exception("exception message") def django_project_redirect(request): return HttpResponseRedirect("https://www.djangoproject.com/") def no_trailing_slash_external_redirect(request): """ RFC 2616 3.2.2: A bare domain without any abs_path element should be treated as having the trailing `/`. Use https://testserver, rather than an external domain, in order to allow use of follow=True, triggering Client._handle_redirects(). """ return HttpResponseRedirect("https://testserver") def index_view(request): """Target for no_trailing_slash_external_redirect with follow=True.""" return HttpResponse("Hello world") def upload_view(request): """Prints keys of request.FILES to the response.""" return HttpResponse(", ".join(request.FILES)) class TwoArgException(Exception): def __init__(self, one, two): pass def two_arg_exception(request): raise TwoArgException("one", "two")