STAY INFORMED
following content serves as a personal note and may lack complete accuracy or
certainty.
Minimal-Mistakes instruction
Useful vscode Shortcut Keys
Unix Commands
npm Commands
Vim Commands
Git Note
Useful Figma Shortcut Keys
Personal Blog Project_2
Personal Blog Project_1 Personal Blog Project_3
Create View
Add path for create view.
# urls.py
urlpatterns = [
path('', views.index, name='index'),
path('posts/', views.PostListView.as_view(), name='post-list'),
path('posts/<int:postId>/', views.PostDetailView.as_view(), name='post-detail'),
path('posts/create/', views.PostCreateView.as_view(), name='post-create'),
]
Create a class to render form page.
# views.py
from django.views.generic import CreateView
from .forms import PostForm
from django.urls import reverse
class PostCreateView(CreateView):
model = Post # create a new 'Post' object based on 'Post'
form_class = PostForm # get input from user using class
template_name = 'posts/postForm.html' # render assigned template
# redirect to 'post-detail' url if an object successfully created
def get_success_url(self):
return reverse('post-detail', kwargs={'postId': self.object.id})
Django automatically checks the validation so if there is an problem for post request, get_success_url function is not executed and error message is returned.
reverse function
# postForm.html
<form method="post">{% csrf_token %}
<h3>Title</h3>
<p>{{form.title}}</p>
{% for error in form.title.errors %}
<p>{{error}}</p>
{% endfor %}
<h3>Content</h3>
<p>{{form.content}}</p>
{% for error in form.content.errors %}
<p>{{error}}</p>
{% endfor %}
<input type="submit" value="Create">
</form>
csrf_token is required for security.
Change href in postList.html for create button.
# postList.html
<a href={% url 'post-create' %}>create</a>
Now when create hyperlink is clicked, moves to form page.
and it works
Form CSS
Modify postForm.html
{% extends './base.html' %} {% load static %} {% block css %} <link
rel="stylesheet" href={% static 'posts/css/form.css' %}> {% endblock css%} {%
block container%}
<form method="post">
{% csrf_token %}
<h3>Title</h3>
<p>{{form.title}}</p>
{% for error in form.title.errors %}
<p class="error">{{error}}</p>
{% endfor %}
<h3>Content</h3>
<p>{{form.content}}</p>
{% for error in form.content.errors %}
<p class="error">{{error}}</p>
{% endfor %}
<input type="submit" value="Submit" />
</form>
{% endblock container%}
and design it.
There is a problem. You cannot attach form.title, form.content since django form automatically designate it. Need to modify forms.py.
# forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
widgets = {'title': forms.TextInput(attrs={
'class': 'title',
'placeholder': 'this is placeholder'}),
'content': forms.Textarea(attrs={'placeholder': 'need content'})}
Now you can design the title.
.title {
...;
}
Update View
Add path for update view.
urlpatterns = [
path('', views.index, name='index'),
path('posts/', views.PostListView.as_view(), name='post-list'),
path('posts/<int:postId>/', views.PostDetailView.as_view(), name='post-detail'),
path('posts/create/', views.PostCreateView.as_view(), name='post-create'),
path('posts/<int:postId>/edit/', views.PostUpdateView.as_view(), name='post-update'),
]
Pretty same as create view.
class PostUpdateView(UpdateView):
model = Post
form_class = PostForm
template_name = 'posts/postForm.html'
pk_url_kwarg = 'postId' # keyword argument
def get_success_url(self):
return reverse('post-detail', kwargs={'postId': self.object.id})
Delete View
To create delete view, you need post_confirm_delete.html since you are using django internal function and they require it. I roughly made it. But you need csrf token for this as well since form attribute is used.
<p>{{post.title}}</p>
<p>You sure?</p>
<form method="POST">
{% csrf_token %}
<input type="submit" value="delete" />
</form>
class PostDeleteView(DeleteView):
model = Post
template_name = 'posts/post_confirm_delete.html'
pk_url_kwarg = 'postId'
context_object_name = 'post'
def get_success_url(self):
return reverse('post-list')
And I added delete button to test it.
When click the delete button
Once you click the button, the post will be deleted.
Learned New
Seeding
Seeding is the process of populating the database with initial or sample data
Seeding is the process of populating the database with initial or sample data
There is a package that can create a bunch of dump data.
pip install django-seed
and add django_seed in INSTALLED_APPS in settings.py
# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'posts',
'django_seed'
]
Now you can create data.
python manage.py seed posts --number=[number of data]
Or you can add data manually.
First, create a data with title: title_data_01 and content: content_data_01.
After, create json file.
python manage.py dumpdata posts --indent=2 > posts_data.json
I got this json file. you can copy and paste this data and change pk.
[
{
"model": "posts.post",
"pk": 3,
"fields": {
"title": "title_data_01",
"content": "content_data_01",
"createdAt": "2024-07-04T05:57:31.075Z",
"modifiedAt": "2024-07-04T05:57:31.075Z"
}
}
]
Then apply the data to the app.
python manage.py loaddata posts_data.json
Pagination
Execute shell
python manage.py shell
Import Paginator function from django and Post from database model.
from django.core.paginator import Paginator
from posts.models import Post
Assign all objects of Post database to a variable and create pages which has 10 objects each.
posts = Post.objects.all()
pages = Paginator(posts, 10)
More Functions
Method & Attribute | Description | Example |
---|---|---|
{paginator}.count |
Number of items in the paginator | {paginator}.count |
{paginator}.num_pages |
Total number of pages in the paginator | {paginator}.num_pages |
{paginator}.page_range |
Range of pages in the paginator | {paginator}.page_range |
{paginator}.page(num) |
Page object for the specified page number | {paginator}.page(1) |
{page}.has_next() |
Whether the page has a next page | {page}.has_next() |
{page}.has_previous() |
Whether the page has a previous page | {page}.has_previous() |
{page}.has_other_pages() |
Whether the page has other pages | {page}.has_other_pages() |
{page}.number |
Current page number | {page}.number |
{page}.object_list |
List of objects on the page | {page}.object_list |
{page}.paginator |
Paginator of the page | {page}.paginator |
{page}.next_page_number() |
Number of the next page | {page}.next_page_number() |
{page}.previous_page_number() |
Number of the previous page | {page}.previous_page_number() |
{page}.start_index() |
Index of the first item on the page (1-based) | {page}.start_index() |
{page}.end_index() |
Index of the last item on the page (1-based) | {page}.end_index() |
After, modify postList template and in postList class views.py.
class PostListView(ListView):
model = Post
template_name = 'posts/postList.html'
context_object_name = 'posts'
ordering = ['-createdAt']
paginate_by = 10
page_kwarg = 'page'
{% extends './base.html' %}
{% load static %}
{% block css%}
<link rel="stylesheet" href={% static 'posts/css/style.css' %}>
{% endblock css%}
{% block header %}
<h1>Personal Blog</h1>
<a href={% url 'post-create' %}>create</a>
{% endblock header %}
{% block container%}
{% if page_obj.object_list %}
<table>
<tr>
<th>Title</th>
<th>Updated</th>
</tr>
{% for post in page_obj.object_list %}
<tr>
<td><a href={% url 'post-detail' post.id %}>{{post.title}}</a></td>
{% if post.modifiedAt.day == today.day %}
<td>{{post.modifiedAt|time:"H:i"}}</td>
{% else %}
<td>{{post.modifiedAt.month}} / {{post.modifiedAt.day}}</td>
{% endif%}
</tr>
{% endfor%}
</table>
<div class="paginator">
{% if page_obj.has_previous %}
<a href="?page=1" class="first">first</a>
<a href="?page={{ page_obj.previous_page_number }}" class="prev">prev</a>
{% endif %}
<span>
<p>{{page_obj.number}} of {{page_obj.paginator.num_pages}}</p>
</span>
{% if page_obj.has_next %}
<a href="?page={{page_obj.next_page_number}}" class="next">next</a>
<a href="?page={{page_obj.paginator.num_pages}}" class="last">last</a>
{% endif %}
</div>
{% else %}
<div class="blank">
<p>No Content</p>
</div>
{% endif %} {% endblock container%}