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

3 minute read

Programming languages used

  • django

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%}

des1

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%}

des3

‘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)

des4

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>

des5

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%}

des6 des7

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>

des8

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.