유저앱을 어카운츠앱으로 변환하면서 상세코드에 뺴먹고 안바꾼거 있음!
근데 공부하는 사람이라면 이정도 오류는 스스로 찾아서 수정하시길...!
1. 작업 디렉토리 만들기(루트폴더)
mkdir [프로젝트_폴더명]
cd [프로젝트_폴더명]
2. 가상환경 설정 (프로젝트 격리를 위해)
깃이그노어 만들고 밴브폴더 넣어두기
필요한 것 : Django, Pillow
python -m venv venv
#가상환경 활성화
깃배쉬 (Windows): source venv/Scripts/activate
맥 (Mac) / 리눅스: source venv/bin/activate
#리콰이어 있으면 다운로드
pip install -r requirements.txt
#리콰이어 없으면 받아서 저장
pip install django
pip freeze -> requirments.txt
#끄는법
deactivate
3. 프로젝트, 앱 생성
django-admin startproject config .
python manage.py startapp accounts
python manage.py startapp post
4. config/settings.py에 앱 추가하기
'''
기존 코드에 끼워넣기
'''
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'accounts',
'post',
]
LANGUAGE_CODE = "ko-kr"
TIME_ZONE = "Asia/Seoul"
TEMPLATES = [
{
"DIRS": [BASE_DIR / "templates"],
}
]
'''
아래부터는 코드 추가
'''
AUTH_USER_MODEL = "users.CustomUser"
# 미디어 파일 설정
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
# 로그인/로그아웃 리다이렉트 설정
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'
5. 앱 models.py 작성
'''
accounts/models.py
'''
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
profile_image = models.ImageField(upload_to='profile_images/', null=True, blank=True)
bio = models.TextField(max_length=500, blank=True)
'''
post/models.py
'''
from django.db import models
from django.conf import settings
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
6. 앱 마그레, 마그렛 하기
python manage.py makemigrations accounts post
python manage.py migrate
7. admin 계정 만들기
python manage.py createsuperuser
8. forms.py 작성
# accounts/forms.py
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'profile_image', 'bio')
# post/forms.py
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content']
9. 프로젝트 urls.py 설정
# config/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("posts.urls")),
path("users/", include("users.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
10. 앱 urls.py 설정
'''
accounts/urls.py
'''
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
path('signup/', views.signup, name='signup'),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('profile/', views.user_profile, name='user_profile'),
]
'''
post/urls.py
'''
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_create, name='post_create'),
path('post/<int:pk>/edit/', views.post_update, name='post_update'),
path('post/<int:pk>/delete/', views.post_delete, name='post_delete'),
]
11. views.py 작성
'''
accounts/views.py
'''
from django.shortcuts import render, redirect
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from .forms import CustomUserCreationForm
def signup(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST, request.FILES)
if form.is_valid():
user = form.save()
login(request, user)
return redirect('post_list')
else:
form = CustomUserCreationForm()
return render(request, 'users/signup.html', {'form': form})
@login_required
def user_profile(request):
return render(request, 'users/profile.html', {'user': request.user})
'''
post/views.py
'''
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from .models import Post
from .forms import PostForm
def post_list(request):
posts = Post.objects.all().order_by('-created_at')
return render(request, 'posts/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'posts/post_detail.html', {'post': post})
@login_required
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'posts/post_form.html', {'form': form})
@login_required
def post_update(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.user != post.author:
return redirect('post_list')
if request.method == 'POST':
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'posts/post_form.html', {'form': form})
@login_required
def post_delete(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.user != post.author:
return redirect('post_list')
if request.method == 'POST':
post.delete()
return redirect('post_list')
return render(request, 'posts/post_confirm_delete.html', {'post': post})
12. 기본 템플릿 작성
<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Django Board{% endblock %}</title>
</head>
<body>
{% include 'navbar.html' %}
<main>
{% block content %}
{% endblock %}
</main>
{% include 'footer.html' %}
</body>
</html>
<!-- templates/navbar.html -->
<nav>
<ul>
<li><a href="{% url 'post_list' %}">홈</a></li>
{% if user.is_authenticated %}
<li><a href="{% url 'user_profile' %}">프로필</a></li>
<li><a href="{% url 'logout' %}">로그아웃</a></li>
{% else %}
<li><a href="{% url 'login' %}">로그인</a></li>
<li><a href="{% url 'signup' %}">회원가입</a></li>
{% endif %}
</ul>
</nav>
<!-- templates/footer.html -->
<footer>
<p>© 2025 Django Board. All rights reserved.</p>
</footer>
13. 유저앱 템플릿
<!-- templates/accounts/signup.html -->
{% extends 'base.html' %}
{% block title %}회원가입{% endblock %}
{% block content %}
<div class="form-container">
<h2>회원가입</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">가입하기</button>
</form>
<p>이미 계정이 있으신가요? <a href="{% url 'login' %}">로그인</a></p>
</div>
{% endblock %}
<!-- templates/accounts/login.html -->
{% extends 'base.html' %}
{% block title %}로그인{% endblock %}
{% block content %}
<div class="form-container">
<h2>로그인</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">로그인</button>
</form>
<p>계정이 없으신가요? <a href="{% url 'signup' %}">회원가입</a></p>
</div>
{% endblock %}
<!-- templates/accounts/profile.html -->
{% extends 'base.html' %}
{% block title %}{{ user.username }}님의 프로필{% endblock %}
{% block content %}
<div class="profile-container">
<h2>프로필</h2>
<div class="profile-info">
{% if user.profile_image %}
<img src="{{ user.profile_image.url }}" alt="프로필 이미지" width="300">
{% endif %}
<h3>{{ user.username }}</h3>
<p>{{ user.bio|default:"소개글이 없습니다." }}</p>
</div>
<div class="user-posts">
<h3>작성한 게시글</h3>
{% for post in user.post_set.all %}
<div class="post-item">
<a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a>
<span>{{ post.created_at|date:"Y-m-d" }}</span>
</div>
{% empty %}
<p>작성한 게시글이 없습니다.</p>
{% endfor %}
</div>
</div>
{% endblock %}
14. 포스트앱 템플릿
<!-- templates/post/post_list.html -->
{% extends 'base.html' %}
{% block title %}게시글 목록{% endblock %}
{% block content %}
<div class="post-list">
<h2>게시글 목록</h2>
{% if user.is_authenticated %}
<a href="{% url 'post_create' %}" class="btn-create">글쓰기</a>
{% endif %}
{% for post in posts %}
<div class="post-item">
<h3><a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a></h3>
<div class="post-meta">
<span>작성자: {{ post.author.username }}</span>
<span>작성일: {{ post.created_at|date:"Y-m-d H:i" }}</span>
</div>
</div>
{% empty %}
<p>게시글이 없습니다.</p>
{% endfor %}
</div>
{% endblock %}
<!-- templates/post/post_detail.html -->
{% extends 'base.html' %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<div class="post-detail">
<h2>{{ post.title }}</h2>
<div class="post-meta">
<span>작성자: {{ post.author.username }}</span>
<span>작성일: {{ post.created_at|date:"Y-m-d H:i" }}</span>
{% if post.updated_at != post.created_at %}
<span>수정일: {{ post.updated_at|date:"Y-m-d H:i" }}</span>
{% endif %}
</div>
<div class="post-content">
{{ post.content|linebreaks }}
</div>
{% if user == post.author %}
<div class="post-actions">
<a href="{% url 'post_update' post.pk %}" class="btn-edit">수정</a>
<a href="{% url 'post_delete' post.pk %}" class="btn-delete">삭제</a>
</div>
{% endif %}
<a href="{% url 'post_list' %}" class="btn-back">목록으로</a>
</div>
{% endblock %}
<!-- templates/post/post_form.html -->
{% extends 'base.html' %}
{% block title %}
{% if form.instance.pk %}
게시글 수정
{% else %}
새 게시글 작성
{% endif %}
{% endblock %}
{% block content %}
<div class="form-container">
<h2>
{% if form.instance.pk %}
게시글 수정
{% else %}
새 게시글 작성
{% endif %}
</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">저장</button>
<a href="{% url 'post_list' %}" class="btn-cancel">취소</a>
</form>
</div>
{% endblock %}
<!-- templates/post/post_confirm_delete.html -->
{% extends 'base.html' %}
{% block title %}게시글 삭제{% endblock %}
{% block content %}
<div class="delete-confirm">
<h2>게시글 삭제</h2>
<p>정말로 "{{ post.title }}" 게시글을 삭제하시겠습니까?</p>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn-delete">삭제</button>
<a href="{% url 'post_detail' post.pk %}" class="btn-cancel">취소</a>
</form>
</div>
{% endblock %}
끗! 서버 켜보기
python manage.py runserver
'Today I learned' 카테고리의 다른 글
WIL 디장고의 관례 (0) | 2025.01.17 |
---|---|
Django - Cookie와 Session (0) | 2025.01.17 |
Djaneiro - Django Snippets 사용법 (5) | 2025.01.15 |
2025.01.13 디제이앙고 연습 (0) | 2025.01.14 |
2025.01.10 Django 기본 구조 이해하기: 모델, URL, 뷰, 폼, 템플릿 (5) | 2025.01.10 |