CRUD logic
190408
django fake-insta
CRUD 복습
-
c9과 장고2.2버젼의 충돌로 버젼관리 필요
-
장고버젼 2.2에서 2.1.8으로 다운그레이드( 지우고 재설치)
1
2
$ pip uninstall django
$ pip install django==2.1.8
- 기능이 추가될 때마다 git을 할 예정
1
2
$ django-admin startproject insta
$ django-admin startapp posts
-
기본 설정
1
2
3
# setting.py
ALLOWED_HOSTS = ["*"]
INSTALLED_APPS = ['posts',] # 추가
1
2
3
4
5
6
7
8
# insta-urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('posts/', include('posts.urls'))
]
1
2
3
4
5
6
7
8
9
# posts-urls.py
from django.urls import path
from . import views
app_name = 'posts'
urlpatterns = [
path('', views.list, name='list'),
]
1
2
3
4
5
# posts-views
from django.shortcuts import render
def list(request):
pass
- 여기까지 기본 설정, commit 남기기
-
커밋시점은 개인적이나 기능이 추가될 때 하는게 일반적
-
모델생성
1
2
3
4
from django.db import models
class Post(models.Model):
content = models.CharField(max_length=100)
- 모델생성 후 마이그레이션
1
2
3
4
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py runserver $IP:$PORT
-
commit
-
공용폴더 설정을 위해
1
2
3
4
# setting.py
TEMPLATES = [
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
- 루트에 templates폴더 생성
- templates폴더에 base.html 생성
1
2
# base.html
1
2
3
4
5
# views.py
from django.shortcuts import render
def list(request):
return render(request, "posts/list.html")
- list.html 은 posts폴더 안에 templates생성후 posts폴더 안에 생성해야함
1
2
3
4
5
6
7
8
# list.html
{% extends 'base.html' %}
{% block body %}
<h1>여기는 리스트 페이지</h1>
{% endblock %}
-
Nav bar만들기
- bootstrap , fontawesome
- new / mypage링크 달기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>insta</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
</head>
<body>
<nav class="navbar sticky-top navbar-expand-lg navbar-light bg-light px-5">
<a class="navbar-brand" href="#">
<i class="fab fa-instagram"></i> | Instagram
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarSupportedContent">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="#">New</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">MyPage</a>
</li>
</ul>
</div>
</nav>
<div class="container">
{% block body %}
{% endblock %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
-
commit
-
CRUD작성
-
Create
1
2
# posts-urls.py
path('create/', views.create, name='create'), # 추가
- 모델폼 - forms.py생성
- ModelForm
- 폼은 자동으로 html코드 작성 없이 form을 만들어줌
- 많을수록 더 편함
- input tag만 존재
- 입력 시 오류가 발생하면 폼에 입력되어 있던 내용이 그대로 유지됨
1
2
3
4
5
6
7
8
9
# posts-forms.py
# 선언
from django import forms
from .models import Post
class PostForm(forms.ModelForm): # forms안에 ModelForm을 상속
class Meta:
model = Post
fields = '__all__'
1
2
3
4
5
6
7
8
9
10
11
# posts-views.py
from .forms import PostForm
def create(request):
# 1. get방식으로 데이터를 입력할 form을 요청한다
if(request.method == "POST"):
pass
else:
# 2. PostForm을 인스턴스화 시켜서 form이라는 변수에 저장
form = PostForm()
# 3. form을 담아서 create.html을 보내줌
return render(request, "posts/list.html", {"form":form})
1
2
3
4
5
6
7
8
9
10
11
12
13
# posts-create.html
{% extends "base.html" %}
{% block body %}
<form action="" method="post">
# action이 ""인 이유 : post와 get방식 모두 create로 보내기만 하면 되기 때문에
## action에 "" 비어있으면 자기 자신으로 다시 요청을 보냄 (posts/create로)
### 즉 get방식으로 들어오면 자기 자신을 다시 불러 post방식으로 처리
#### 그리고 create와 update를 하나의 html로 관리하기 위해 action을 비워둠
{% csrf_token %}
<input type="submit">
</form>
{% endblock %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# posts-views.py
def create(request):
# 1번부터 순서대로
# 1. get방식으로 데이터를 입력할 form을 요청한다
# 4. 사용자는 데이터를 input에 입력해서 post방식으로 요청
# 9. 사용자가 적절한 데이터를 입력해서 다시 post방식으로 요청
if(request.method == "POST"):
# 5. post방식으로 저장요청을 받고, 데이터를 받아 PostForm에 넣어서 인스턴스화 한다
# 10. 5번과 동일
form = PostForm(request.POST) # 앞의 PostForm은 모델폼이고 request.Post는 입력한 내용
# 6. 데이터 validation (검증)
# 11. 6번과 동일
if(form.is_valid()):
# 12. 적정한 데이터가 들어온 경우, 데이터를 저장하고 list페이지로 리다이렉트
form.save()
return redirect('posts:list')
else:
# 7. 적절하지 않은 데이터가 들어온 경우
## else는 생략해도 됨
pass
else:
# 2. PostForm을 인스턴스화 시켜서 form이라는 변수에 저장
form = PostForm()
# 3. form을 담아서 create.html을 보내줌
# 8. 사용자가 입력한 데이터는 form에 담아진 상태로 다시 form을 담아서 create.html을 보내준다.
## 8번은 사용자가 잘못 입력 했을 때 그대로 담아진 내용을 보내주는 것(ModelForm의 장점?)
return render(request, "posts/create.html", {"form":form})
- admin 페이지에서 확인
1
2
3
4
5
# admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
- 폼을 예쁘게 바꾸기 위해
1
$ pip install django-bootstrap4
- create.html 수정
1
2
3
4
5
6
7
8
9
10
11
12
# create.html
{% extends "base.html" %}
{% load bootstrap4 %}
{% block body %}
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit">
</form>
{% endblock %}
- 리스트 페이지
1
2
3
4
5
6
# views.py
from .models import Post
def list(request):
posts = Post.objects.all()
return render(request, "posts/list.html", {'posts':posts})
- include = posts/_post.html에 끼워넣기
- for문 만큼
1
2
3
4
5
6
7
8
9
# list.html
{% extends 'base.html' %}
{% block body %}
{% for post in posts %}
{% include 'posts/_post.html' %}
{% endfor %}
{% endblock %}
1
2
3
4
5
6
7
# _post.html
<div class="card">
<img src="..." class="card-img-top" alt="...">
<div class="card-body">
<p class="card-text"></p>
</div>
</div>
-
commit
-
Update
1
2
# posts-urls.py
path('<int:id>/update/', views.update, name="update"),
- create.html을 form.html로 수정
1
2
3
4
5
6
7
8
9
10
11
12
13
# views.py
def update(request, id):
post = Post.objects.get(id=id)
if(request.method == "POST"):
form = PostForm(request.POST, instance=post)
if(form.is_valid()):
form.save()
return redirect("posts:list")
else:
# post를 인스턴스로
form = PostForm(instance=post)
return render(request, 'posts/form.html', {"form":form})
-
commit
-
base.html수정
1
2
3
# base.html url 경로 수정
<a class="navbar-brand" href="{% url 'posts:list' %}">
<a class="nav-link" href="{% url 'posts:create' %}">New</a>
1
2
# _post.html 수정버튼 달기
<a href="{% url 'posts:update' post.id %}" class="btn btn-warning">수정</a>
-
Delete
1
2
# urls.py
path('<int:id>/delete/', views.delete, name="delete"),
1
2
3
4
5
# views.py
def delete(request, id):
post = Post.objects.get(id=id)
post.delete()
return redirect("posts:list")
1
2
3
# _post.html
<a href="{% url 'posts:delete' post.id %}" class="btn btn-danger">삭제</a>