[PYTHON] Create a simple CRUD app using Django's generic class view

Introduction

Previously, I made an app that allows you to easily post, edit, and delete with Rails, so I tried to reproduce it with Django. With the theme of "Posting the impressions of the book you read", you can post the title of the book and short impressions. I have the code source below.

Rails version: https://github.com/Sn16799/Bookers.git Django version: https://github.com/Sn16799/DjangoBookers.git

environment

OS: centos7 Django: 3.0.6 Python: 3.8.3

Launch the app

$ python manage.py start project mysite
$ cd mysite
$ python manage.py startapp bookers

Directory structure

Below templates, I added forms.py manually.

mysite/
  bookers/
    templates/
      books/
        index.html
        detail.html
        update.html
    admin.py
    forms.py
    models.py
    urls.py
    views.py
  mysite/
    settings.py
    urls.py

Create / enable model

-** Creating a Model **

Edit models.py.

bookers/models.py


from django.db import models
from django.urls import reverse

# Create your models here.
class Book(models.Model):
	title = models.CharField('title', max_length=50)
	body = models.CharField('body', max_length=200)

	def get_absolute_url(self):
		return reverse('bookers:detail', kwargs={'pk': self.pk})

I want to keep the structure as simple as possible, so the only columns are title and body. Below that, get_absolute_url is a method that specifies the transition destination after saving the data in Model. When I tried to create the data without writing this, I got the error "Please define get_absolute_url !!" (For the method, this site archives / 402 # Post) is very detailed and easy to understand).

-** Add app to project **

Add the following to settings.py.

mysite/settings.py


INSTALLED_APPS = [
    'bookers.apps.BookersConfig', #Add here
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Perform a migration to notify Django of Model changes.

$ python manage.py makemigrations bookers
$ python manage.py migration

Now you are ready to develop your app.

Create an administrator site

Django has an admin site by default. It will be convenient for future implementation, so let's set the admin side first.

mysite/urls.py


from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('bookers/', include('bookers.urls', namespace='django_bookers')),
    path('admin/', admin.site.urls),
]

bookers/admin.py


from django.contrib import admin
from django_bookers.models import Book

# Register your models here.
admin.site.register(Book)

You can create an administrator account by executing the following command. You will be asked for your name, email address and password, so enter any value.

$ python manage.py createsuperuser

If you visit http://127.0.0.1:8000/admin/, you will see the admin site. If you log in with the user information you created earlier, you can add and manage records for each app. We recommend that you make some records at this stage.

URL settings

First, set the URL.

bookers/urls.py


from django.urls import path
from . import views

app_name='bookers'
urlpatterns = [
    # bookers/
    path('', views.CreateView.as_view(), name='index'),
    # bookers/1/
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    # bookers/1/update/
    path('<int:pk>/update/', views.UpdateView.as_view(), name='update'),
    # bookers/1/delete/
    path('<int:pk>/delete', views.delete, name='delete'),
]

Write the template file easily. I'll fix it later, so it's okay if you write the characters that tell you what the screen is.

templates/books/index.html


<h1>this is INDEX view !!!</h1>

templates/books/update.html


<h1>this is UPDATE view !!!</h1>

templates/books/detail.html


<h1>this is DETAIL view !!!</h1>

View implementation

Edit views.py as follows.

bookers/views.py


from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect
from django.views import generic
from .models import Book
from .forms import BookForm

class CreateView(generic.CreateView):
	model = Book
	form_class = BookForm
	template_name = 'books/index.html'

	#Get all Book model data, book_Store in list
	def get_context_data(self):
		context = super().get_context_data()
		context['book_list'] = Book.objects.all()
		return context

class DetailView(generic.DetailView):
	model = Book
	template_name = 'books/detail.html'
	context_object_name = 'book'

class UpdateView(generic.UpdateView):
	model = Book
	template_name = 'books/update.html'
	form_class = BookForm

def delete(request, pk):
	book = get_object_or_404(Book, id=pk)
	book.delete()
	return redirect('bookers:index')

After saving the contents, check if each screen is displayed correctly. List screen (index.html): http://127.0.0.1:8000/bookers Edit screen (update.html): http://127.0.0.1:8000/bookers/1/update Detail screen (detail.html): http://127.0.0.1:8000/bookers/1/detail

Example) List screen index.jpg

If the characters you wrote in the html file are displayed, the routing settings are complete.

Posting function

I want to display the list of posts and new posts on the same screen, so I will create a function with CreateView. ListView is also prepared for list display, but I stopped it because it seemed to be complicated to implement new posts. django.views.generic seems to have many other useful generic views.

python:bookers.views.py



class CreateView(generic.CreateView):
        model = Book
        form_class = Bookform
        template_name = 'books/index.html'

	def get_context_data(self):
		context = super().get_context_data()
		context['book_list'] = Book.objects.all()
		return context

In CreateView, you can pass any data with the get_context_data method. Here, in order to list the posts, we are getting all the data of the Book model with the name book_list. For the arguments and methods that can be used in the class view, see here.

bookers/templates/books/index.html


<h1>Books</h1>

<table>
  <thead>
	<tr>
  	  <th>Title</th>
	  <th>Body</th>
	</tr>
  </thead>
  <tbody>
	{% for book in book_list %}
	<tr>
	  <td>{{ book.title }}</td>
	  <td>{{ book.body }}</td>
	  <td>
		<a href="{% url 'bookers:detail' book.id %}">Detail</a>
		<a href="{% url 'bookers:update' book.id %}">Update</a>
		<a href="{% url 'bookers:delete' book.id %}">Delete</a>
	  </td>
	</tr>
	{% endfor %}
  </tbody>
</table>

<h2>New Book</h2>
<form method="post">
  {{ form.as_p }}
  {% csrf_token %}
  <input type="submit" name="Submit">
</form>

If you go to http://127.0.0.1:8000/bookers/ and you see the "Books" heading and the post form screen, you're good to go. At this point, if you fill out the form and press the Submit button, you'll be redirected to the details screen with "this is DETAIL view !!!" (the appropriate wording you just entered). However, please be assured that if you return to the list, the saved posts will be displayed properly.

index.jpg ↑ List screen that is terribly murky because the screen is not decorated

Details page

This is a detailed screen that allows you to extract and display only one post, which changes when you press the "Detail" link on the list screen. In this app, the columns are only the title and the text, and you can see all of them in the list, so it is not convenient, but I will make it for practice.

bookers/views.py


class DetailView(generic.DetailView):
	model = Book
	template_name = 'books/detail.html'
	context_object_name = 'book'

Since you specified book in context_object_name, you can now call the data with the name book in the template. For some reason, I was able to display the contents of the column even if I wrote object, but I have specified the book for easy understanding.

bookers/templates/books/detail.html


<p>
  <strong>Title:</strong>
  {{ book.title }}
</p>

<p>
  <strong>Body:</strong>
  {{ book.body }}
</p>

<a href="{% url 'bookers:update' book.id %}">Update</a>
 |
<a href="{% url 'bookers:index' %}">Back</a>

Let's go to http://127.0.0.1:8000/bookers/1/detail. detail.jpg ↑ Since nothing is too much, I also put a link to the edit screen (Update) and list screen (Back).

Editing function

Allows you to edit the posted data later.

bookers/views.py


class UpdateView(generic.UpdateView):
	model = Book
	template_name = 'books/update.html'
	form_class = BookForm

bookers/templtes/books/update.html


<h1>Updating Book</h1>

<form method="post">
  {{ form.as_p }}
  <button type="submit">Update</button>
</form>

<a href="{% url 'bookers:detail' book.id %}">Detail</a>
 | 
<a href="{% url 'bookers:index' %}">Back</a>

(Because it's an update process, the method of the form is patch! I was confident and wrote patch, and I fell in love with it. Rails' common sense is Django's insane.)

If you visit http://127.0.0.1:8000/bookers/1/update, you will see a form with data.

update.jpg

I didn't intend to provide an example, but the title of the book I posted was incorrect and I would like to correct it. Correct some parts and press the "Update" button.

detail_after_update.jpg Redirected to the details screen and fixed the correct title!

Delete function

bookers/views.py


def delete(request, pk):
	book = get_object_or_404(Book, id=pk)
	book.delete()
	return redirect('bookers:index')

If you press the delete button on the list screen, you will be redirected to the same screen as it is. Since the deletion confirmation screen was not created this time, the definition of view is also changed to a form starting with def (function-based general-purpose view) unlike other functions.

* About view types

Views created with views.py are broadly divided into ** class-based generic views ** that start with class and ** function-based generic views ** that start with def. Since there are 3 types of screens to create this time, I implemented them in the class-based general-purpose view only for create, detail, and update. With this feature, you can create screens that include CRUD features and forms with less code. However, since you cannot create a view without a template, only delete is a function-based general-purpose view. (For details, click here](https://qiita.com/dai-takahashi/items/7d0187485cad4418c073))

Afterword

I was addicted to errors here and there, but I managed to create an app with the minimum functionality. This time, I didn't do the Flash message when posting / updating or deleting was successful, and the decoration with CSS, so I would like to implement it later.

reference

How to make an app in general

Create your first Django app (Django documentation)

How to create a non-class based delete function: DjangoBrothers

About class-based generic views

Introduction to class-based generic views in Django and sample usage Collect Django's generic class views and mention the implementation

List of class-based generic views: Code for Django

Arguments and methods that can be used in class-based general-purpose views: Ganesha's Antenna Shop

Other

Use success_url and get_success_url, reverse and reverse_lazy properly: Ganesha's Antenna Shop

About get_absolute_url (method used for model): IT Engineer Lab

Recommended Posts

Create a simple CRUD app using Django's generic class view
Create a shogi game record management app using Django 4 ~ Create View ~
Create a CRUD API using FastAPI
Create a simple GUI app in Python
Create a simple web app with flask
Ajax in Django (using generic class view)
Create a beauty pageant support app using PyLearn2
Create a Mac app using py2app and Python3! !!
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 1 ~
DJango Note: From the beginning (using a generic view)
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 2 ~
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 3 ~
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 4 ~
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 5 ~
Create a (simple) REST server
Create a simple textlint server
Create a shogi game record management app using Django 2-Database settings-
Create a shogi game record management app using Django 6 ~ Template division ~
Create and deploy a Django (PTVS) app using Azure Table storage
Create a simple scheduled batch using Docker's Python Image and parse-crontab
Create a python GUI using tkinter
Create a nested dictionary using defaultdict
Creating a simple table using prettytable
Creating a simple app with flask
Create a C wrapper using Boost.Python
Create a shogi game record management app using Django 3 ~ Django default management site settings ~
Create a Python function decorator with Class
Build a blockchain with Python ① Create a class
Create a graph using the Sympy module
Create a GUI app with Python's Tkinter
[Python] Create a Batch environment using AWS-CDK
Create a Python-GUI app in Docker (PySimpleGUI)
Create a dataframe from excel using pandas
Create a web app that converts PDF to text using Flask and PyPDF2