더보기
75일 차 회고.
주말 동안 스트레스받을 일이 있어서 잠을 많이 잤더니 어젯밤에 잠이 잘 오지 않았다. 그래서 잠을 충분히 자지 못해서 하루 종일 피곤했던 것 같다. 장고도 내일이면 끝나는데 어떻게 하는지는 알겠지만 막상 혼자서 하려고 하면 잘 되지 않아서 답답하다.
1. Django
1-1. Login - Django
가상환경 생성
uv venv .venv -p 3.13
.\.venv\Scripts\activate
uv pip install -r .\requirements.txt
# requirements.txt
django
mysqlclient
Django 프로젝트 생성
django-admin startproject config .
Django 앱 생성
python manage.py startapp user
python manage.py startapp todolist
templates 생성
mkdir templates
mkdir .\templates\base
mkdir .\templates\user
mkdir .\templates\todolist
static 생성
mkdir static
mkdir .\static\css
코드 작성
- TEMPLATE
<!--templates/user/index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User Page</title>
</head>
<body>
<h1>User List</h1>
</body>
</html>
<!--templates/todolist/index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>To-do List Page</title>
</head>
<body>
<h1>To-do List</h1>
</body>
</html>
- VIEW
# user/views.py
from django.shortcuts import render
def index(request):
return render(request, 'user/index.html')
# todolist/views.py
from django.shortcuts import renderfrom django.shortcuts import render
def todolist(request):
return render(request, 'todolist/todolist.html')
- URL RESOLUTION
# config/urls.py
from django.urls import path, include
urlpatterns = [
path('user/', include('user.urls')),
path('', include('todolist.urls')),
]
# user/urls.py
from django.urls import path
from .views import index
urlpatterns = [
path('', index, name='user'),
]
# todolist/urls.py
from django.urls import path
from .views import todolist
urlpatterns = [
path('', todolist, name='todolist'),
]
- SETTING
# config/settings.py
import os
from pathlib import Path
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'user',
'todolist',
]
...
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db',
'USER': 'django_root',
'PASSWORD': 'r1234',
'HOST': 'localhost',
'PORT': '3306',
}
}
...
STATIC_URL = 'static/'
STATIC_PATH = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = (STATIC_PATH,)
...
서버 실행
python manage.py runserver
Login 기능 구현
- TEMPLATE
<!--templates/base/index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block stylesheet %} {% endblock %}
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
<!--templates/user/login.html-->
{% extends 'base/index.html' %}
{% block title %}Login Page{% endblock %}
{% block stylesheet %}
{% load static %}
<link rel="stylesheet" href="{% static 'css/login.css' %}">
{% endblock %}
{% block content %}
<div class="wrapper">
<h2>Login</h2><br>
{% if messages %}
{% for message in messages %}
<h2 style="color: #b22222;">{{message}}</h2>
{% endfor %}
{% endif %}
<form action="#" method="POST">
{% csrf_token %}
<div class="input-box">
<input type="text" placeholder="Enter your username" required name="username">
</div>
<div class="input-box">
<input type="password" placeholder="Enter your password" required name="password">
</div>
<div class="policy">
</div>
<div class="input-box button">
<input type="Submit" value="Login">
</div>
<div class="text">
<h3>Don't have an account? <a href="{% url 'user-register' %}">Register now</a></h3>
</div>
<div class="text">
<h3>Forgot Password? <a href="{% url 'user-login' %}">Reset</a></h3>
</div>
</form>
</div>
{% endblock %}
<!--templates/user/register.html-->
{% extends 'base/index.html' %}
{% block title %}Register Page{% endblock %}
{% block stylesheet %}
{% load static %}
<link rel="stylesheet" href="{% static 'css/register.css' %}">
{% endblock %}
{% block content %}
<div class="wrapper">
<h2>Register</h2><br>
{% if messages %}
{% for message in messages %}
<h2 style="color: #b22222;">{{message}}</h2>
{% endfor %}
{% endif %}
<form action="#" method="POST">
{% csrf_token %}
<div class="input-box">
<input type="text" placeholder="Create a username" required name="username">
</div>
<div class="input-box">
<input type="email" placeholder="Enter your email" required name="email">
</div>
<div class="input-box">
<input type="password" placeholder="Enter your password" required name="password">
</div>
<div class="policy">
</div>
<div class="input-box button">
<input type="Submit" value="Register">
</div>
<div class="text">
<h3>Do you have an account? <a href="{% url 'user-login'%}">Login now</a></h3>
</div>
<div class="text">
<h3>Forgot Password? <a href="{% url 'user-register'%}">Reset</a></h3>
</div>
</form>
</div>
{% endblock %}
<!--templates/todolist/todolist.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>To-do List Page</title>
</head>
<body>
<h1>To-do List</h1>
<a href="{% url 'user-logout'%}">Logout</a>
</body>
</html>
- VIEW
# user/views.py
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login, logout
from django.contrib import messages
def user_register(request):
if request.user.is_authenticated:
return redirect(to='todolist')
elif request.method == 'POST':
username = request.POST.get('username').strip()
email = request.POST.get('email').strip()
password = request.POST.get('password').strip()
if User.objects.filter(username=username).exists():
messages.error(request, 'Username already exists')
return redirect(to='user-register')
elif not username or not email or not password:
messages.error(request, 'Email and password are required')
return redirect(to='user-register')
new_user = User.objects.create_user(
username=username,
email=email,
password=password
)
new_user.save()
return redirect(to='user-login')
return render(request, 'user/register.html')
def user_login(request):
if request.user.is_authenticated:
return redirect(to='todolist')
elif request.method == 'POST':
username = request.POST.get('username').strip()
password = request.POST.get('password').strip()
auth_user = authenticate(username=username, password=password)
if not auth_user:
messages.error(request, 'Invalid username or password')
return redirect(to='user-login')
login(request, auth_user)
return redirect(to='todolist')
return render(request, 'user/login.html')
def user_logout(request):
logout(request)
return redirect(to='user-login')
- URL RESOLUTION
# user/urls.py
from django.urls import path
from .views import user_register, user_login, user_logout
urlpatterns = [
path('register/', user_register, name='user-register'),
path('login/', user_login, name='user-login'),
path('logout/', user_logout, name='user-logout'),
]
To-do List 기능 구현
- MODEL
# todolist/models.py
from django.db import models
from django.contrib.auth.models import User
class TodoList(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
status = models.BooleanField(default=False)
def __str__(self):
return self.title
- TEMPLATE
<!--templates/base/index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block stylesheet %} {% endblock %}
{% block script %} {% endblock %}
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
<!--templates/todolist/todolist.html-->
{% extends 'base/index.html' %}
{% block stylesheet %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
{% endblock %}
{% block script %}
<script src="//d.bablic.com/snippet/6288d4c3c4c5800001a91242.js?version=3.9"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
{% endblock %}
{% block title %}To-do List Page{% endblock %}
{% block content %}
<h1 class="fs-1 fw-bold p-2 text-center" style="color:lightseagreen;">To-do List</h1>
<section class="vh-100" style="background-color: #eee;">
<div class="container text-center font-monospace py-5 h-100">
<div class="row d-flex justify-content-center align-items-center h-100">
<div class="col col-lg-9 col-xl-7">
<div class="card rounded-3">
<div class="card-body p-4">
{% if messages %}
{% for message in messages %}
<h4 style="color: crimson;">{{message}}</h4>
{% endfor %}
{% endif %}
<h2 class="fw-bold my-3 pb-3">Todo List</h2>
<form method="POST" class="row row-cols-lg-auto g-3 justify-content-center align-items-center mb-4 pb-2">
{% csrf_token %}
<div class="col-12">
<div class="form-outline">
<input type="text" id="form1" class="form-control" name="task" placeholder="Enter a task here"/>
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-outline-primary w-40">Add Task</button>
<a href="{% url 'user-logout' %}">
<button type="button" class="btn btn-outline-info w-40">Logout</button>
</a>
</div>
</form>
{% if todo_list|length > 0 %}
<table class="table mb-4">
<thead>
<tr>
<th scope="col">Todo Item</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{% for i in todo_list %}
<tr>
<td>{{i.title}}</td>
{% if i.status == True %}
<td>Complete</td>
{% else %}
<td>In progress</td>
{% endif %}
<td>
<a href="{% url 'todolist-update' i.id %}"><button type="submit" class="btn btn-outline-success col-5">Finished</button></a>
<a href="{% url 'todolist-delete' i.id %}"><button type="submit" class="btn btn-outline-danger col-5">Delete</button></a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<h4 style="color: crimson;">No tasks available</h4>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
- VIEW
# todolist/views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .models import TodoList
@login_required(login_url='user-login')
def todolist(request):
if request.method == 'POST':
task = request.POST.get('task').strip()
if TodoList.objects.filter(title=task, user=request.user).exists():
messages.error(request=request, message='Task already exists')
return redirect(to='todolist')
elif not len(task):
messages.error(request=request, message='Task cannot be empty')
return redirect(to='todolist')
new_task = TodoList(title=task, user=request.user)
new_task.save()
content = {
"todo_list": TodoList.objects.filter(user=request.user).order_by('id'),
}
return render(request, 'todolist/todolist.html', content)
@login_required(login_url='user-login')
def update_task(request, task_id):
task = TodoList.objects.get(id=task_id, user=request.user)
task.status = True
task.save()
return redirect(to='todolist')
@login_required(login_url='user-login')
def delete_task(request, task_id):
TodoList.objects.filter(id=task_id, user=request.user).delete()
return redirect(to='todolist')
- URL RESOLUTION
# todolist/urls.py
from django.urls import path
from .views import todolist, update_task, delete_task
urlpatterns = [
path('', todolist, name='todolist'),
path('todolist-update/<int:task_id>', update_task, name='todolist-update'),
path('todolist-delete/<int:task_id>', delete_task, name='todolist-delete'),
]
'SK네트웍스 Family AI캠프 10기 > Daily 회고' 카테고리의 다른 글
| 77일차. AWS - IAM & EC2 (0) | 2025.04.30 |
|---|---|
| 76일차. Django (0) | 2025.04.29 |
| 74일차. Django (0) | 2025.04.25 |
| 73일차. Django (0) | 2025.04.24 |
| 72일차. JavaScript & Django (0) | 2025.04.23 |