DEV Community

suyaa
suyaa

Posted on

Django cheatsheet - Views

View are something that accepts a request, and returns some kind of a response.

In the render() function, you can pass a context that are variables you can pass to your template.

how to add a new view

  • define the URL in your-project/your-app/urls.py
  • add a view in your-projects/your-app/views/new-view.py
  • import the view in your-projects/your-app/views/__init__.py

shortcuts: render, redirect

from django.shortcuts import render, redirect

def index(request):
  students = Students.objects.all()
  context = { "students": students }
  return render("index.html", context)

def new(request):
  # save a new student
  return redirect("your_app:new")
Enter fullscreen mode Exit fullscreen mode

Note that you can't pass a context with a redirect; you can only pass a URL and query parameters.

messages

https://docs.djangoproject.com/en/4.1/ref/contrib/messages/#using-messages-in-views-and-templates

If you want to use "messages" (e.g. flash messages, toast messages in other frameworks), you can use the messages framework.

Add this import,

from django.contrib import messages
Enter fullscreen mode Exit fullscreen mode

... and call the messages like this in your views.

messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')
Enter fullscreen mode Exit fullscreen mode

The template can show the messages like this:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}
Enter fullscreen mode Exit fullscreen mode

It' s important to iterate all the messages, otherwise the messages will not be cleared.

from django.contrib import messages

# view to create new student
def new(request):
  if request.method == "POST":
    # do something with the form 
    student.save()
    # send messages
    messages.success(request, "saved student")
Enter fullscreen mode Exit fullscreen mode

formsets

You can use formsets when you want to handle multiple records of the same model (e.g. multiple students).

Formsets come in handy because they will do the validation on all the records for you.

In your view, you can define your formset like this:

# your_project/your_app/views/new.py

from django.forms import modelformset_factory
from django.shortcuts import redirect, render

from your_app.models import Student

def new(request):
  # fields: defines which fields to show in the form
  # extra: defines how many extra rows you want in the form, on top of existing records
  StudentFormset = modelformset_factory(Student, fields=["last_name", "first_name", "photo"], extra=10)

  if request.method == "GET":
    # by default, formset will populate all records in that model
    # specify the set of records to be "no students"
    formset = StudentFormset(query=Student.objects.none())
    context = { "formset": formset }
    return render("your_app/new.html", context)

  if request.method == "POST":
    # populate the formset with user input
    formset = StudentFormset(request.POST, request.FILES)

    if formset.is_valid():
      # save the entire formset
      formset.save()

      # make sure to redirect after a POST request
      return redirect("your_app:new")
Enter fullscreen mode Exit fullscreen mode

If you need to specify a foreign key on a formset, you do have to iterate through each record like so:

# your_project/your_app/views/new.py

if formset.is_valid():
  # get the instances via the save method
  # but don't commit yet
  instances = formset.save(commit=False)
  for student in instances:
    student.school_id = 1
    # populate school_id and save one by one
    student.save()
Enter fullscreen mode Exit fullscreen mode

In this case, an "atomic transaction" might be needed, where if either all transactions succed, or no transaction succeeds.

You can use the decorator or the with: block (please see the documentation for the latter option; I prefer decorators with less indent).

# define a helper function with a decorator
from django.db import transaction

@transaction.atomic
def save_students_with_school(formset, school_id):
  instances = formset.save(commit=False)
  for student in instances:
    student.school_id = school_id
    # populate school_id and save one by one
    student.save()
Enter fullscreen mode Exit fullscreen mode
# call them in your view like this

if formset.is_valid():
  # call the atomic transaction
  save_students_with_school(formset, 1)
Enter fullscreen mode Exit fullscreen mode

Top comments (0)