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_1
Personal Blog Project_2 Personal Blog Project_3
Setup
mkdir personal-blog
cd personal-blog
pyenv local django-envs
django-admin startproject personalBlog
cd personalBlog
python manage.py startapp posts
python manage.py migrate
# setting.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'posts', # add this
]
I will simply create main page, posts-list page, post-detail page and create post page.
# /personalBlog/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('posts.urls')),
]
# /posts/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('posts/', views.postList, name='post-list'),
]
# /posts/views.py
from django.shortcuts import render
def index(request):
return redirect('post-list')
def postList(request):
return render(request, 'posts/postList.html')
index function will handle if there is no path in url, it will redirect and render postList page. If there is no index function, it will response 404.
<!-- /posts/templates/posts/base.html -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href={% static 'posts/css/styles.css' %}>
<title>Document</title>
</head>
<body>
{% block post-container %} {% endblock post-container %}
</body>
</html>
<!-- /posts/templates/posts/index.html -->
{% extends './base.html' %} {% load static %} {% block post-container%}
<p>hello</p>
{% endblock post-container%}
Index Page
All setup now. I am going to make real index page.
{% extends './base.html' %}
{% load static %}
{% block header %}
<h1>Personal Blog</h1>
<a href="">create</a>
{% endblock header %}
{% block post-container%}
{% if posts %}
<p>There is at least one post</p>
{% else %}
<div class="blank">
<p>No Content Created</p>
</div>
{% endif %}
{% endblock post-container%}
‘posts’ in if statement will be context variable which is passed from database. I haven’t created database, so I will do it now.
Database Setup
I need title, content, created time, modified time for database structure.
#models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=50)
content = models.TextField()
createdAt = models.DateTimeField(verbose_name="Date Created", auto_now_add=True)
modifiedAt = models.DateTimeField(verbose_name="Date Modified", auto_now=True)
def __str__(self):
return self.title
verbose_name make the time more readable. If you don’t use it, default variable in django will automatically used.
After, register the database.
python manage.py makemigrations
python manage.py migrate
double check it in /migrations/0001_initial.py
# Generated by Django 3.2.25 on 2024-06-28 21:59
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Post',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50)),
('content', models.TextField()),
('createdAt', models.DateTimeField(auto_now_add=True, verbose_name='Date Created')),
('modifiedAt', models.DateTimeField(auto_now=True, verbose_name='Date Modified')),
],
),
]
Admin
You can simply handle database in admin site. First, need to create the account
python manage.py createsuperuser
And register the database in admin site.
# admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
I will create one date for test.
python manage.py shell
Post.objects.create(title="test",
... content="test content",
... )
Frontend
Post List
And modify html
{% if posts %}
{% for post in posts %}
<table>
<tr>
<th>Title</th>
<th>Created</th>
<th>Updated</th>
</tr>
<tr>
<td><a href="">{{post.title}}</a></td>
<td>{{post.createdAt}}</td>
<td>{{post.modifiedAt}}</td>
</tr>
</table>
{% endfor%}
{% else %}
<div class="blank">
<p>No Content</p>
</div>
I want to make date shorter like if today == updated date, show only time and else, show the date with form 6 / 28.
If today != updated date
<td>{{post.modifiedAt.month}} / {{post.modifiedAt.day}}</td>
If today = updated date
<td>{{post.modifiedAt|time:"H:i"}}</td>
Now need to get today’s day. You can get in views.py and pass it through context variable.
from datetime import date # need this module
def postList(request):
today = date.today()
posts = Post.objects.all()
context = {
'posts': posts,
'today': today,
}
return render(request, 'posts/postList.html', context)
{% if post.modifiedAt.day == today.day %}
<td>{{post.modifiedAt|time:"H:i"}}</td>
{% else %}
<td>{{post.modifiedAt.month}} / {{post.modifiedAt.day}}</td>
{% endif%}
Post Detail
# urls.py
urlpatterns = [
path('', views.index, name='index'),
path('posts/', views.postList, name='post-list'),
path('posts/<int:postId>/', views.postDetail, name='post-detail'),
]
# views.py
def postDetail(request, postId):
post = Post.objects.get(id=postId)
context = {'post': post}
return render(request, 'posts/postDetail.html', context)
<!-- postDetail.html -->
{% extends './base.html' %}
{% block container%}
<h3>{{post.title}}</h3>
<div>created: {{post.createdAt}}</div>
<div>modified: {{post.modifiedAt}}</div>
<br />
<div>{{post.content|linebreaksbr}}</div>
{% endblock container%}
On postList page, I want to make when title is clicked, move to the content of the post detail page.
<!-- postList.html -->
<td><a href={% url 'post-detail' post.id %}>{{post.title}}</a></td>
Learned New
You can change postList, postDetail function to a class using generic view method.
from django.views.generic import ListView, DetailView
class PostListView(ListView):
model = Post # create a new 'Post' object based on 'Post'
template_name = 'posts/postList.html' # render assgined template
context_object_name = 'posts' # context
ordering = ['-createdAt'] # ascending order
# to get today's date
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['today'] = date.today()
return context
class PostDetailView(DetailView):
model = Post # create a new 'Post' object based on 'Post'
template_name = 'posts/postDetail.html' # render assgined template
pk_url_kwarg = 'postId' # keyword argument
context_object_name = 'post' # context
and change url.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'),
]
These work totally same as the previous one.