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
OS: centos7 Django: 3.0.6 Python: 3.8.3
$ python manage.py start project mysite
$ cd mysite
$ python manage.py startapp bookers
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
-** 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.
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.
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>
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
If the characters you wrote in the html file are displayed, the routing settings are complete.
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.
↑ List screen that is terribly murky because the screen is not decorated
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. ↑ Since nothing is too much, I also put a link to the edit screen (Update) and list screen (Back).
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.
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.
Redirected to the details screen and fixed the correct title!
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.
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))
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.
Create your first Django app (Django documentation)
How to create a non-class based delete function: DjangoBrothers
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
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