A Django Blog In VS Code — Class-Based-View & CRUD
How To Create A Blog in VS Code — Part VIII — DjangoSeries Episode # 11
This is all about django class_based view & CRUD.
INDEXES:
Create
Read(List)
Update
Delete
Welcome!
We should use class_based views (CBVs) in our applications.
It’s better to stick with the Django convention unless you have a very good reason not to.
CBVs are generic views that provide abstract classes implementing common web development tasks built by professionals and covering all common behaviors.
They have an amazing structured API, and you can use all of the advantages of object-oriented programming when you use CBVs.
It makes your source code more clear and readable.
Forget the pain of using Django standard view functions for listings, CRUD operations, forms processing, etc
This post will deal with it: CBVs.
More details on this view class at Classy Class-Based Views by Refresh Oxford. 👏👏👏.
Let’s get started!
Django Naming Convention For Views(V) Models(M) Templates(T)
As Django is MVT, first thing first:
This is the my name_convention_table
used hereafter:
00#Step — This is a continuation of this post.
If we have only used function_based generic views
in our Django project so far and find out that they are limited, we should think about class_based view
instead. Let’s get it on!
READ — LIST — : Modus operandi V(iew) U(rls) T(emplate)
01#Step — V(iew):
GoTo blog\views.py
, and add these lines:
...
from django.views.generic import ListView# def home(request):
# context = {
# 'posts': Post.objects.all()
# }
# return render(request, 'blog/home.html', context)
class PostListView(ListView):
model = Post
# context_object_name = 'object_list'
ordering = ['-date_posted']...
02#Step —U(rls)
: GoTo blog\urls.py
, and add these lines:
from django.urls import path
from blog import views
from blog.views import PostListViewurlpatterns = [
# path('', views.home, name='blog-home'),
path('', PostListView.as_view(), name='post_list'),
path('about/', views.about, name='about_page'),
]
Just be aware of these points:
1-
Comment out the old home
function-based-view (def home()
);
2-
Let’s say that we want to use this postListView
class instead of our current home function as our home by importing ListView
CBV;
3-
How Django knows about the old posts as we pass no context?
The generic view will query the database to get all records for the specified model (Post
) then render a template located at /djang_project/blog/templates/blog/post_list.html
(which we will created below).
Within the template you can access the list of posts with the template variable named object_list
OR post_list
(i.e. generically "the_model_name_list
").
4-
We are showing our newest blog-post first by just adding this line:
ordering = ['-date_posted'] —
the minus sign do the trick!
03#Step — T(emplate):
Create blog\post_list.html
, and add these lines:
Just be aware of these points:
1-
If you compare to the old home.html
you’ll see that now we are looping throught object_list
instead of posts
;
All of Django’s database backends automatically convert strings into the appropriate encoding for talking to the database. They also automatically convert strings retrieved from the database into strings. You don’t even need to tell Django what encoding your database uses: that is handled transparently. (from https://docs.djangoproject.com/en/4.0/ref/unicode/)
2-
If you compare to the commented code, you’ll find fewer lines of code. That’s the premium to stick with Django convention!
Clean and valid code means less confusing bugs to fix, easier handover to other developers and better code security.
Django is a free and open source Python web framework that helpfully solves common development challenges and allows you build flexible, well-structured applications. (from https://www.toptal.com/django/django-top-10-mistakes)
3-
The post are now ordered in reverse order, as usual in the industry. Django’s generic views really shine when it comes to presenting views of your database content. Because it’s such a common task, Django comes with a handful of built-in generic views to help generate list and detail views of objects.
DETAIL — : Modus operandi V(iew) U(rls) T(emplate)
04#Step — V(iew):
GoTo blog\views.py
, and add these lines:
...
from django.views.generic import ... DetailView
...class PostDetailView(DetailView):
model = Post...
05#Step — U(rls)
: GoTo blog\urls.py
, and add these lines:
...
from blog.views import ... PostDetailView
...
urlpatterns = [
...
path('post/<int:pk>/', PostDetailView.as_view(),
name='post_detail'),
...
]
06#Step — T(emplate):
Create blog\post_detail.html
, and add these lines:
Just be aware of these points:
1-
There is no loop here;
2-
object
are used instead of post
; While this view is executing, self.object
will contain the object that the view is operating upon. [Django doc link]
3-
Each post now have it’s own page! This is the detail Django template’s rule. Fine! Now let’s create a post…
CREATE — : Modus operandi V(iew) U(rls) T(emplate)
07#Step — V(iew):
GoTo blog\views.py
, and add these lines:
...
from django.views.generic import ... CreateView
from django.contrib.auth.mixins import LoginRequiredMixin...class PostCreateView(CreateView):
model = Post
fields = ['title', 'content'] def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)...
08#Step — U(rls)
: GoTo blog\urls.py
, and add these lines:
...
from blog.views import ... PostCreateViewurlpatterns = [
...
path('post/new', PostCreateView.as_view(), name='post_create'),
...
]
09#Step — T(emplate):
Create blog\post_form.html
, and add these lines:
Just be aware of these points:
1-
You would expect post_create but Django’s convention is post_form;
2-
The template just prints the form
; by working in Django we come across patterns at a higher level of abstraction. Well, that’s marvelous, indeed!
10#Step — Modify blog\models.html
to:
...
from django.urls import reverse...def __str__(self):
return self.titledef get_absolute_url(self):
return reverse("post_detail", kwargs={"pk": self.pk})
11#Step — Distinguish which link-button
clicked in django:
<li class="nav-item">
<a class="nav-link" href="{% url 'post_create' %}">New Post</a></li>
{% if object.author == user %}
<div>
<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url
'post_update' object.id %}">Update</a>
<a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url
'post_delete' object.id %}">Delete</a>
</div>
{% endif %}
12#Step — As we can’t use decorators with class lets use mixins
:
That’s basically just a class that we inherit from that will add that login functionality to the view so let’s go ahead and add this in:
Modify blog\views.py
file to:
...
CreateViewfrom django.contrib.auth.mixins import LoginRequiredMixin
...class PostCreateView(LoginRequiredMixin, CreateView):
....
UPDATE — : Modus operandi V(iew) U(rls) T(emplate)
13#Step — V(iew):
GoTo blog\views.py
, and add these lines:
...
from django.views.generic import ... UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin...class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Post
fields = ['title', 'content']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form) def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False...
14#Step — U(rls)
: GoTo blog\urls.py
, and add these lines:
...
from blog.views import ...,PostUpdateViewurlpatterns = [
...
path('post/<int:pk>/update/', PostUpdateView.as_view(),
name='post_update'),
...
]
15#Step — T(emplate):
For the template it’s just going to use that same post form template that we created for the create view at step#09
, so we don’t even need to add another template. Let’s go on…
Now another operation:
DELETE — : Modus operandi V(iew) U(rls) T(emplate)
16#Step — V(iew):
GoTo blog\views.py
, and add these lines:
17#Step — U(rls)
: GoTo blog\urls.py
, and add these lines:
...
from blog.views import ..., PostDeleteViewurlpatterns = [
...
path('post/<int:pk>/delete/', PostDeleteView.as_view(),
name='post_delete'),
...
]
18#Step — T(emplate):
Create blog\post_confirm_delete.html
, and add these lines:
Ups, we almost forget….GoTo django_project/settings.py
and change theses lines:
# Redirecting to homeLOGIN_REDIRECT_URL = 'post_list'
ACCOUNT_LOGOUT_REDIRECT_URL = 'post_list'
LOGIN_URL = 'login'
The final step is:
19#Step — run the server:
python manage.py runserver
20#Step — login as userTest4
and try to post:
http://127.0.0.1:8000/post/4/
21#Step — Let’s try /post/new/ even logged-off:
Now, log in as userTest4
and Post a new blog by clicking New Post
:
That’s all Folks!
I would like to remind everyone, especially those Python’s lovers, soon we will be back with Posts Pagination & Quick DB Population.
See you around. Bye!
👉 git
References & Credits
Python Django Tutorial: Full-Featured Web App by Corey Schafer
Django Documentations — Unicode data — by djangoproject.com
Top 10 Mistakes that Django Developers Make by toptal.com
Requeriments.txt: pip freeze creates some weird path instead of the package version by stackoverflow.com
How to Create User Sign Up View by Vitor Freitas
👌️Classy Class-Based Views — Detailed descriptions, with full methods and attributes, for each of Django’s class-based generic views by Refresh Oxford
Getting started with the web by Mozilla Foundation
🙀️Wireflow — free, online and open source tool for creating beautiful user flow prototypes by https://wireflow.co/
🙀️excalidraw.com by excalidraw is free, online and open source tool to draw :)
🙀️Django Project Blueprint — Awesome Free Tutorial — Check it out! — learn by building thing with Matthew Segal
Classy Class-Based Views — Detailed descriptions, with full methods and attributes, for each of Django’s class-based generic views.
👌️Official Django Documentations — All authentication views — This is a list with all the views django.contrib.auth
provides by https://docs.djangoproject.com/
Related Posts
00#Episode — DjangoSerie — Django Intro — How To Build your First App in Python Django Framework — DjangoSeries
01#Episode — DjangoSerie — Django MTV In VS Code — How To Install Django Inside Virtual VS Code
02#Episode — DjangoSerie — Can You Solve This in Python? — Here is A Basic Python Question!
03#Episode — DjangoSerie — JUNGLE-DJANGO Webpage! This Is My New Django Netflix Clone Page!
04#Episode — DjangoSerie — A Django Blog In VS Code — Quick Start! — Part_I
05#Episode — DjangoSerie — A Django Blog In VS Code — Database, Migrations & Queries — Part_II
06#Episode — DjangoSerie — A Django Blog In VS Code — Bootstrap, Tailwind CSS — Part_III
07#Episode — DjangoSerie — A Django Blog In VS Code — Forms & Validations — Part_IV
08#Episode — DjangoSerie — A Django Blog In VS Code — Login & Logout — Part_V
09#Episode — DjangoSerie — A Django Blog In VS Code — Upload Profile Picture — Part_VI
10#Episode — DjangoSerie — A Django Blog In VS Code — Update & Resize Picture — Part_VII
11#Episode — DjangoSerie — A Django Blog In VS Code — Class-Based-View & CRUD — Part_VIII (this one :)
12#Episode — DjangoSerie — A Django Blog In VS Code — Posts Pagination & Quick DB Population — Part_IX
13#Episode — DjangoSerie — A Django Blog In VS Code — Self-Service Django Password Reset — Part_X
14#Episode — DjangoSerie — A Django Blog In VS Code — Heroku Deploy — How To Push Your Site To Productio — Part_XI (this last one…whew!)
HowTo Run this Tutorial - From the Scratch - In your Machine:)Annotations: Quick Start - video #TakeTheFirstStepToLearnDjango0 - Download DJG_10/Django_project from my git repo;
1 - On your desktop, create a dir and named it as Tutorial_11;
2 - Inside this paste the previous Django_project file;
3 - GoTo vscode Terminal (command prompt) and ...
4 - Run this quick_script
(copy/paste inside you terminal and hit enter and wait until
Pillow is up and running...):python -m venv djangoEnv
djangoEnv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install django
python -m django --version
pip install django-crispy-forms
pip install Pillow5- GoTo Step#01 of this tutorial.And you are good to go!
Sharing is caring.
by me
“Once we believe in ourselves, we can risk curiosity, wonder, spontaneous delight, or any experience that reveals the human spirit.”
-E. Cummings.