Django ORM
Object Relational Mapping : OOP 를 사용하여 호환되지 않는 시스템 간에 데이터를 변환해주는 기술

ORM Create
QuerySet API
ORM 에서 데이터 검색, 필터링, 정렬 등 에 사용되는 도구
QuerySet : Django ORM 을 통해 만들어진 자료형으로 데이터베이스에서 전달 받은 객체 목록
QuerySet 등록
Django shell : django 안에서 실행되는 python shell
데이터 객체 생성 방법
첫번째
>>> article = Article()
>>> article
<Article: Article object (None)>
>>> article.title = 'first'
>>> article.content = 'django!'
>>> article.save()
>>> article
<Article: Article object (1)>
>>> article.title
'first'
두번째
세번째
>>> Article.objects.create(title='third', content='django')
<Article: Article object (3)>
# save 없이 바로 생성
ORM Read
>>> Article.objects.all()
<QeurySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (3)>]>
>>> Article.objects.get(pk=1)
<Article: Article object (1)>
>>> Article.objects.filter(content='django~')
<QuerySet [<Article: Article object (2)>]>
ORM Update
>>> article = Article.objects.get(pk=1)
>>> article.title = 'change'
>>> article.save()
>>> article.title
'change'
ORM Delete
>>> article = Article.objects.get(pk=1)
>>> article.delete()
(1, {' articles.Article ' : 1})
>>> Article.objects.get(pk=1)
DoesNotExist: Article matching query does not exist.
ORM Read with view
URL 파일 분리
# project crud/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns =[
path('admin/', admin.site.urls),
path('articles', include('articles.urls')),
]
# articles/url.py
from django.urls import path
from . import views
app_name = 'articles'
urlpatterns =[
path('', views.index, name='index'),
]
전체 게시글 조회
# articles/views.py
from .models import Article
def index(request):
articles = Article.objects.all()
context = {
'articles': articles,
}
return render(request, 'articles/index.html', context)
<!-- articles/index.html -->
<h1>Articles</h1>
<hr>
{% for article in articles %}
<p>글 번호: {{ article.pk }}</p>
<p>글 제목: {{ article.title }}</p>
<p>글 내용: {{ article.content }}</p>
<hr>
{% endfor %}

단일 게시글 조회
# articles/urls.py
urlpatterns =[
path('', views.index, name='index'),
path('<int:pk>/', views.detail, name='detail'),
]
# articles/views.py
def detail(request, pk):
article = Article.objects.get(pk=pk)
context = {
'article': article,
}
return render(request, 'articles/detail.html', context)
<h2>DETAIL</h2>
<h3>{{ article.pk }} 번째 글 </h3>
<hr>
<p>제목: {{ article.title }}</p>
<p>내용: {{ article.content }}</p>
<p>작성 시각: {{ article.created_at }}</p>
<p>수정 시각: {{ article.updated_at }}</p>
<hr>
<a href="{% url 'articles:index' %}">[back]</a>

ORM Create with view
# articles/urls.py
urlpatterns =[
path('', views.index, name='index'),
path('<int:pk>/', views.detail, name='detail'),
path('new/', views.new, name='new'),
path('create/', views.create, name='create'),
]
# articles/views.py
def new(request):
return render(request, 'articles/new.html')
def create(request):
title = request.GET.get('title')
content = request.GET.get('content')
article = Article(title=title, content=content)
article.save()
return render(request, 'articles/create.html')
<!-- templates/articles/new.html -->
<h1>NEW</h1>
<form action="{% url 'articles:create' %}" method="GET">
<div>
<label for="title">Title: </label>
<input type="text" name="title" id="title">
</div>
<div>
<label for="content">Content: </label>
<textarea name="content" id="content"></textarea>
</div>
<input type="submit">
</form>
<hr>
<a href="{% url 'articles:index' %}">[back]</a>


ORM Delete with view
# articles/urls.py
urlpatterns =[
path('', views.index, name='index'),
path('<int:pk>/', views.detail, name='detail'),
path('new/', views.new, name='new'),
path('create/', views.create, name='create'),
path('<int:pk>/delete/', views.delete, name='delete'),
]
# articles/views.py
def delete(request, pk):
article = Article.objects.get(pk=pk)
article.delete()
return redirect('articles:index')
<!-- articles/detail.html -->
<h2>DETAIL</h2>
<form action="{% url 'articles:delete' article.pk %}" method="POST">
{% csrf_token %}
<input type="submit" value="DELETE">
</form>
<a href="{% 'articles:index' %}">[back]</a>
ORM Update with view
# articles/urls.py
urlpatterns =[
path('', views.index, name='index'),
path('<int:pk>/', views.detail, name='detail'),
path('new/', views.new, name='new'),
path('create/', views.create, name='create'),
path('<int:pk>/delete/', views.delete, name='delete'),
path('<int:pk>/edit/', views.edit, name='edit'),
path('<int:pk>/update/', views.update, name='update'),
]
# articles/views.py
def edit(request, pk):
article = Article.objects.get(pk=pk)
context = {
'article': article,
}
return render(request, 'articles/edit.html', context)
def update(request, pk):
article = Article.objects.get(pk=pk)
article.title = request.POST.get('title')
article.content = request.POST.get('content')
article.save()
return redirect('articles:detail', article.pk)
<!-- articles/detail.html -->
<h2>DETAIL</h2>
<a href="{% url 'articles:edit' article.pk %}">EDIT</a><br>
<form action="{% url 'articles:delete' article.pk %}" method="POST">
{% csrf_token %}
<input type="submit" value="DELETE">
</form>
<a href="{% 'articles:index' %}">[back]</a>
<!-- articles/edit.html -->
<h1>EDIT</h1>
<form action="{% url 'articles:update' article.pk %}" method="POST">
{% csrf_token %}
<div>
<label for="title">Title: </label>
<input type="text" name="title" id="title" value="{{ article.title }}">
</div>
<div>
<label for="content">content: </label>
<textarea name="content" id="content" value="{{ article.content }}"></textarea>
</div>
<input type="submit">
</form>
<hr>
<a href="{% url 'articles:index' %}">[back]</a>
Render vs Redirect
render : template 호출
redirect : url 호출 (인자에 작성된 주소로 다시 요청을 보냄, context 못넘겨줌)
GET vs Post
- get : 데이터를 url 뒤에 붙여서 보냄
- ex) http://www.naver.com/index/?parameter=value
- post : 데이터를 body 에 넣어서 보냄
- ex) body { "parameter":"value", ... }
CSRF (Cross Site Request Forgery)
사이트 간 요청 위조
웹사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를 특정 웹사이트에 요청하게 하는 공격
CSRF token : CSRF 방어 방법 중 하나
- 서버가 사용자 입력 데이터에 token 부여
- 매 요청마다 해당 token 을 포함시켜 전송
- 서버에서 요청 받을 때마다 token 이 유효한지 검증
Django 에서 form 문 아래에 {% csrf_token %} 을 넣으면 사용 가능
QuerySet reference
https://docs.djangoproject.com/en/3.2/ref/models/querysets/