2021. 5. 16. 18:24ㆍLIKELION 9th
지난 이야기🌿
6주 차에는 장고(Django)를 시작했다.
7주 차(2021.05.10-2021.05.13)
7주 차에는 지난 세션에 이어서 장고에 대해 배웠다. blog라는 이름의 프로젝트를 만들고 CRUD 기능을 구현했다.
* CRUD는 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말이다.(출처 위키백과)
장고로 블로그 만들기
- 제목과 내용을 넣을 수 있는 글쓰기 기능 구현
- 글을 쓰면 제목과 내용, 작성일로 글 생성
- 글 수정 및 삭제 기능 구현
1. 장고 프로젝트와 앱 생성하기
1) 가상환경 만들고 프로젝트와 앱 생성하기
$ python -m venv myven #가상환경 생성
$ . myvenv/Scripts/activate #가상환경 실행
$ pip install django #장고 설치
$ django-admin startproject blog #'blog' 프로젝트 생성
$ cd blog #'blog' 프로젝트로 이동
$ python manage.py startapp main #'main' 앱 생성
$ python manage.py runserver #http://127.0.0.1:8000/ 웹 서버 실행
2) 프로젝트 내 settings.py에 만든 앱 등록하기
3) 앱 내 templates 폴더 만들기
* 자세한 내용은 지난 글 참고
2. models.py 작성하기
블로그의 글에는 제목, 내용, 작성일 등의 내용이 들어간다. 장고 안의 모델을 사용해 이 내용을 데이터베이스에 저장해보자.
1) 앱 내 models.py 작성하기
#models.py
from django.db import models
class Write(models.Model):
title = models.CharField(max_length=50) #글자 수가 제한된 텍스트 정의(짧은 문자열)
contents = models.TextField() #글자 수 제한이 없는 긴 텍스트 정의
updated_at = models.DateTimeField(auto_now=True) #날짜와 시간 정의
- Write 모델을 만들었다(클래스 이름의 첫 글자는 대문자로 써야 한다).
- models는 Write가 장고 모델임을 의미한다.
* auto_now_add=True로 하면 최초 글 작성 시간을, auto_now=Ture로 하면 글이 수정될 때마다의 시간을 반영한다.
2) 데이터베이스에 등록하기
$ python manage.py makemigrations
$ python manage.py migrate
3) admin.py 작성하기
models.py에서 만든 class Write를 admin.py에 등록하자.
#admin.py
from django.contrib import admin
from .models import Write
# Register your models here.
admin.site.register(Write)
4) http://127.0.0.1:8000/admin 에서 Write 객체 확인하기
- 장고에서 기본으로 제공하는 admin 페이지에서 객체를 확인해 보자.
- 페이지에 접속하기 위해서는 superuser 계정이 필요하다.
$ python manage.py createsuperuser
superuser 계정으로 페이지에 접속하면 아래와 같이 Write 객체를 확인하고 관리할 수 있다.
3. forms.py 작성하기
admin 권한이 없는 일반 사용자가 데이터를 생성, 수정, 삭제할 수 있게 해보자. 장고에서는 form을 통해 models.py 구조에 해당하는 데이터를 입력받을 수 있다.
* 앱 내 forms.py 파일을 직접 만들었다.
#forms.py
from django import forms
from .models import Write
class WriteForm(forms.ModelForm):
class Meta:
model = Write
fields = '__all__'
- Meta 클래스는 어떤 모델을 사용할지, 해당 모델에서 어떤 필드를 사용할지 정의한다.
- fields 값을 '__all__'로 사용하면 모델의 모든 필드("title", "contents", "updated_at")를 가져온다.
4. urls.py - views.py - templates
데이터 준비를 마쳤으니 이제 웹 페이지에 보이게 해보자.
1) urls.py
from django.contrib import admin
from django.urls import path
from main import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.index, name='index'),
path('create/', views.create, name='create'),
path('detail/<int:write_id>', views.detail, name='detail'),
path('update/<int:write_id>', views.update, name='update'),
path('delete/<int:write_id>', views.delete, name='delete'),
]
2) views.py
from django.shortcuts import get_object_or_404, redirect, render
from .forms import WriteForm
from .models import Write
# Create your views here.
def index(request):
all_write = Write.objects.all()
return render(request, 'index.html', {'all_write':all_write})
def create(request):
if request.method == "POST":
create_form = WriteForm(request.POST)
if create_form.is_valid():
create_form.save()
return redirect('index')
else:
create_form = WriteForm()
return render(request, 'create.html', {'create_form':create_form})
def detail(request, write_id):
my_write = get_object_or_404(Write, pk=write_id)
return render(request, 'detail.html', {'my_write':my_write})
def update(request, write_id):
my_write = get_object_or_404(Write, id=write_id)
if request.method == "POST":
update_form = WriteForm(request.POST, instance=my_write)
if update_form.is_valid:
update_form.save()
return redirect('index')
update_form = WriteForm(instance=my_write)
return render(request, 'update.html', {'update_form':update_form})
def delete(request, write_id):
my_write = get_object_or_404(Write, id=write_id)
my_write.delete()
return redirect('index')
3) index.html
#views.py
(···)
def index(request):
all_write = Write.objects.all()
return render(request, 'index.html', {'all_write':all_write})
(···)
<!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">
<title>Document</title>
</head>
<body>
<h1>Donghae Blog</h1>
<div class="create_write">
<a href="{% url 'create'%}"><div class="create_btn">🙋♂️글쓰기🙋♂️</div></a>
</div>
{% for write in all_write %}
<div class="all_write">
<a href = "{% url 'detail' write.id %}">
<div>{{write.id}}</div><br>
<div>{{write.title}}</div><br>
<div>{{write.contents}}</div><br>
<div>{{write.updated_at|date:"Y.m.d"}}</div><br>
<a>
</div>
{% endfor %}
</body>
</html>
- 글쓰기 기능을 위해 버튼을 생성하고 클릭하면 url 'create'로 넘어가도록 설정
- Write 객체를 담은 all_write 변수를 for문을 사용하여 출력
- all_write 변수, 즉 게시물 내용을 클릭하면 url 'detail'로 넘어가도록 설정
4) create.html
#views.py
(···)
def create(request):
if request.method == "POST":
create_form = WriteForm(request.POST)
if create_form.is_valid():
create_form.save()
return redirect('index')
else:
create_form = WriteForm()
return render(request, 'create.html', {'create_form':create_form})
(···)
<!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">
<title>Document</title>
</head>
<body>
<form method="POST", action="">
{% csrf_token %}
{{create_form.as_p}}
<input type="submit" value="제출">
<form>
</body>
</html>
- "POST"요청에 대해 장고에서 기본으로 제공하는 보안 수단인 {% csrf_token %} 태그 사용
- {{create_form.as_p}}를 사용해 각 필드를 p태그 안에서 배치
* CSRF 공격(Cross Site Request Forgery): 웹사이트 취약점 공격의 하나로 사용자의 의지와는 무관하게 수정, 삭제, 등록 등을 웹사이트에 요청하게 하는 공격
5) detail.html
#views.py
(···)
def detail(request, write_id):
my_write = get_object_or_404(Write, pk=write_id)
return render(request, 'detail.html', {'my_write':my_write})
(···)
<!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">
<title>Document</title>
</head>
<body>
{{my_write.id}}번째 글
<br>제목: {{my_write.title}}
<br>내용: {{my_write.contents}}
<br><a href="{% url 'update' my_write.id %}"><button>수정</button><a>
<a href="{% url 'delete' my_write.id %}"><button>삭제</button><a>
</body>
</html>
- detail 메서드에서 id값(int)에 해당하는 객체가 있으면 이를 my_write 변수로 가져오고, 없으면 404 에러 띄우기.
- 수정(update) 및 삭제(delete) 기능을 구현하기 위해 버튼 생성
* pk is the attribute that contains the value of the primary key for the model.
* id is the name of the field created as a primary key by default if none is explicitly specified.
6) update.html
#views.py
(···)
def update(request, write_id):
my_write = get_object_or_404(Write, id=write_id)
if request.method == "POST":
update_form = WriteForm(request.POST, instance=my_write)
if update_form.is_valid:
update_form.save()
return redirect('index')
update_form = WriteForm(instance=my_write)
return render(request, 'update.html', {'update_form':update_form})
(···)
<!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">
<title>Document</title>
</head>
<body>
<form method="POST", action="">
{% csrf_token %}
{{update_form.as_p}}
<button type="submit" value="제출">제출</button>
<form>
</body>
</html>
- update 메서드는 "POST"요청에 대해 id값에 해당하는 인스턴스를 받아서 내용을 불러온다.
- 변수 이름을 제외하면 그 외의 내용은 create와 동일하다.
이제 웹 페이지를 열어서 기능을 확인해보자!
* 네 번째 쓰는 글이라 id값으로 4표시
디자인은 엉망진창이지만 그래도 기능은 구현 완료😅👍
views.py에 메서드마다 변수 이름이 달라서 처음에는 엄청 헷갈렸는데 세 번째 보니까 좀 익숙해졌다,,,
이제 css 파일 만들러 가자🤸♀️
참고자료
Django: 데이터 관계
1. PK & ID > is the attribute that contains the value of the primary key for the model. is the name of the field created as a primary key by default
velog.io
[Django Basic 09] {% csrf_token %}
1. CSRF(Cross Site Request Forgery) : 웹사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등) 를 특정 웹사이트에 요청하게 하는 공격 이미 사용
chagokx2.tistory.com
Django — CRUD 기능 구현
쌩 Django로 기본 CRUD 기능 구현하기
asaprocky123.medium.com
Python Django 강좌 : 제 7강 - Serializers | 076923
Django Serializers
076923.github.io
Model field reference | Django documentation | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
'LIKELION 9th' 카테고리의 다른 글
[멋쟁이 사자처럼] Django로 블로그 만들기3 (댓글 쓰기) (0) | 2021.05.25 |
---|---|
[멋쟁이 사자처럼] Django로 블로그 만들기2 (회원가입, 로그인, 로그아웃) (0) | 2021.05.24 |
[멋쟁이 사자처럼] 장고 시작하기(단어 수 세기 예제✔) (0) | 2021.05.08 |
[멋쟁이 사자처럼] 멋사 9기 아이디에이션(feat. 예비 집사를 위한 웹사이트😺) (0) | 2021.04.30 |
[멋쟁이 사자처럼] HTML과 CSS로 자기소개 웹페이지 만들기 (2) | 2021.04.10 |