11 Build A Blog From Scratch Django
12 Django로 나만의 블로그 만들기
Real Python의 단계별 지침에 따라 Django로 나만의 블로그를 만들어 보세요.
12.1 설정
아래 설명된 단계에 따라 제공된 예제 프로젝트를 로컬 컴퓨터에서 실행할 수 있습니다.
새 가상 환경을 만듭니다.
$ python3 -m venv venv가상 환경을 활성화합니다.
$ source venv/bin/activate아직 설치하지 않은 경우 이 프로젝트의 종속성을 설치합니다.
(venv) $ python -m pip install -r requirements.txt프로젝트에 대한 마이그레이션을 만들고 적용하여 로컬 데이터베이스를 빌드합니다.
(venv) $ python manage.py makemigrations
(venv) $ python manage.py migrateDjango 개발 서버를 실행합니다.
(venv) $ python manage.py runserver블로그가 작동하는 것을 보려면 http://localhost:8000/으로 이동하십시오.
12.2 Django 관리자 사이트 사용
새 게시물을 만들려면 슈퍼유저를 만들어야 합니다.
(venv) $ python manage.py createsuperuser
사용자 이름 (비워두면 'root' 사용): admin
이메일 주소: admin@example.com
비밀번호: RealPyth0n
비밀번호 (다시): RealPyth0n
슈퍼유저가 성공적으로 생성되었습니다.createsuperuser 관리 명령을 실행하면 사용자 이름을 선택하고 이메일 주소를 제공하고 암호를 설정하라는 메시지가 표시됩니다. 이 필드에 자신의 데이터를 사용하고 기억해 두십시오.
http://localhost:8000/admin으로 이동하여 방금 슈퍼유저를 만드는 데 사용한 자격 증명으로 로그인합니다.
12.3 파일: django-blog/blog/__init__.py
12.4 파일: django-blog/blog/admin.py
from blog.models import Category, Comment, Post
from django.contrib import admin
class CategoryAdmin(admin.ModelAdmin):
pass
class PostAdmin(admin.ModelAdmin):
pass
class CommentAdmin(admin.ModelAdmin):
pass
admin.site.register(Category, CategoryAdmin)
admin.site.register(Post, PostAdmin)
admin.site.register(Comment, CommentAdmin)12.5 파일: django-blog/blog/apps.py
from django.apps import AppConfig
class BlogConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "blog"12.6 파일: django-blog/blog/forms.py
from django import forms
class CommentForm(forms.Form):
author = forms.CharField(
max_length=60,
widget=forms.TextInput(
attrs={"class": "form-control", "placeholder": "Your Name"}
),
)
body = forms.CharField(
widget=forms.Textarea(
attrs={"class": "form-control", "placeholder": "Leave a comment!"}
)
)12.7 파일: django-blog/blog/migrations/0001_initial.py
# Generated by Django 4.2.4 on 2023-08-29 12:43
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30)),
],
),
migrations.CreateModel(
name='Post',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255)),
('body', models.TextField()),
('created_on', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
('categories', models.ManyToManyField(related_name='posts', to='blog.category')),
],
),
migrations.CreateModel(
name='Comment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('author', models.CharField(max_length=60)),
('body', models.TextField()),
('created_on', models.DateTimeField(auto_now_add=True)),
('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.post')),
],
),
]12.8 파일: django-blog/blog/migrations/__init__.py
12.9 파일: django-blog/blog/models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=30)
class Meta:
verbose_name_plural = "categories"
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField("Category", related_name="posts")
def __str__(self):
return self.title
class Comment(models.Model):
author = models.CharField(max_length=60)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey("Post", on_delete=models.CASCADE)
def __str__(self):
return f"{self.author} on '{self.post}'"12.10 파일: django-blog/blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.blog_index, name="blog_index"),
path("post/<int:pk>/", views.blog_detail, name="blog_detail"),
path("category/<category>/", views.blog_category, name="blog_category"),
]12.11 파일: django-blog/blog/views.py
from blog.forms import CommentForm
from blog.models import Comment, Post
from django.http import HttpResponseRedirect
from django.shortcuts import render
def blog_index(request):
posts = Post.objects.all().order_by("-created_on")
context = {"posts": posts}
return render(request, "blog/index.html", context)
def blog_category(request, category):
posts = Post.objects.filter(categories__name__contains=category).order_by(
"-created_on"
)
context = {"category": category, "posts": posts}
return render(request, "blog/category.html", context)
def blog_detail(request, pk):
post = Post.objects.get(pk=pk)
form = CommentForm()
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = Comment(
author=form.cleaned_data["author"],
body=form.cleaned_data["body"],
post=post,
)
comment.save()
return HttpResponseRedirect(request.path_info)
comments = Comment.objects.filter(post=post)
context = {"post": post, "comments": comments, "form": form}
return render(request, "blog/detail.html", context)12.12 파일: django-blog/manage.py
관리 작업을 위한 Django의 명령줄 유틸리티입니다.
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "personal_blog.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()12.13 파일: django-blog/personal_blog/__init__.py
12.14 파일: django-blog/personal_blog/asgi.py
personal_blog 프로젝트에 대한 ASGI 구성입니다.
이는 application이라는 모듈 수준 변수로 호출 가능한 ASGI를 노출합니다.
이 파일에 대한 자세한 내용은 다음을 참조하세요. https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
ASGI config for personal_blog project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "personal_blog.settings")
application = get_asgi_application()12.15 파일: django-blog/personal_blog/settings.py
personal_blog 프로젝트에 대한 Django 설정입니다.
Django 4.2.4를 사용하여 ’django-admin startproject’로 생성되었습니다.
이 파일에 대한 자세한 내용은 다음을 참조하세요. https://docs.djangoproject.com/en/4.2/topics/settings/
설정 및 해당 값의 전체 목록은 다음을 참조하세요. https://docs.djangoproject.com/en/4.2/ref/settings/
"""
Django settings for personal_blog project.
Generated by 'django-admin startproject' using Django 4.2.4.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = (
"django-insecure-jl==lja$kjxwf+!=yt@(2oja*6ob8jg#!n*_7#j_a+zrrk2-kr"
)
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"blog.apps.BlogConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "personal_blog.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
BASE_DIR / "templates/",
],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "personal_blog.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"12.16 파일: django-blog/personal_blog/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("blog.urls")),
]12.17 파일: django-blog/personal_blog/wsgi.py
personal_blog 프로젝트에 대한 WSGI 구성입니다.
application이라는 모듈 수준 변수로 호출 가능한 WSGI를 노출합니다.
이 파일에 대한 자세한 내용은 다음을 참조하세요. https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
WSGI config for personal_blog project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "personal_blog.settings")
application = get_wsgi_application()