[day-35] 모델, ORM, CRUD 기본

Joohyung Park·2024년 2월 25일
0

[모두연] 오름캠프

목록 보기
65/95

URL 설계

''
'blog/'
'blog/test' 
'blog/<int:pk>/'

모델 정의

앱의 데이터 구조와 동작을 정의하며, 데이터베이스와의 상호작용을 관리한다.

# blog > models.py

from django.db import models


class Post(models.Model):
    title = models.CharField(max_length=100)
    contents = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True) # 처음 생성될 때에만 자동으로 현재 시간으로 설정
    updated_at = models.DateTimeField(auto_now=True) # 수정될 때마다 자동으로 현재 시간으로 업데이트

파이썬 코드로 DB 다루기

실제 DB를 다루기 전에 확인 가능한 명세서 생성

python manage.py makemigrations

명세서로 실제 DB 다루기

python manage.py migrate

admin 페이지

admin.py에서 설정하며 admin 사이트에서 데이터를 생성, 조회, 수정, 삭제하는 등의 작업을 웹 인터페이스로 수행 가능하다.

# blog > admin.py

from django.contrib import admin
from .models import Post

# Post 모델의 데이터를 admin 사이트에서 보고, 새로운 Post 데이터를 생성하고, 
# 기존의 Post 데이터를 수정하거나 삭제할 수 있습니다.
admin.site.register(Post)

관리자 계정 생성

python manage.py createsuperuser

게시물 명칭 수정

위의 과정까지 진행한 후, 서버를 실행하면 게시물의 제목이 Object... 이런 이상한 형식으로 출력된다.

이는 어떤 것이 제목인지를 명시하지 않아서인데, models.py에서 __str__메서드로 원하는 문자열로 출력하게끔 할 수 있다.

from django.db import models


class Post(models.Model):
    title = models.CharField(max_length=100)
    contents = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True) 
    updated_at = models.DateTimeField(auto_now=True) 

    # 명칭이 제대로 나오도록 정의
    def __str__(self):
        create_time = self.created_at.strftime("%Y-%m-%d %H:%M:%S")
        update_time = self.updated_at.strftime("%Y-%m-%d %H:%M:%S")
        return f"제목: {self.title}, 생성시간: {create_time}, 수정시간: {update_time}"

모델 객체 가져오기

# blog > views.py 수정

from django.shortcuts import render
from .models import Post


def blog_list(request):
    # Post 클래스의 모든 객체를 가져와 blogs에 저장
    blogs = Post.objects.all()
    context = {"db": blogs}
    # 템플릿에 전달
    return render(request, "blog/blog_list.html", context)


def blog_detail(request, pk):
    # pk값이 인자와 일치하는 Post 객체를 가져와 blog에 저장
    blog = Post.objects.get(pk=pk)
    context = {"db": blog}
    return render(request, "blog/blog_detail.html", context)


def blog_test(request):
    return render(request, "blog/blog_test.html")

위와 같이 모델의 Post 클래스 객체를 가져와 사용하도록 한다.

context 안에는 title, contents, created_at, updated_at이 들어 있다. 이를 db라는 키로 접근한다.

하이퍼링크 생성

게시물 제목으로 하이퍼링크를 생성하여 화면상에서 클릭하면 detail 페이지로 들어가도록 구현하였다.

# templates > blog > blog_list.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>게시판</h1>
    <ul>
        {% for post in db %}
            <li>
            # 블로그 글 리스트 하이퍼링크 생성
            # 해당 링크를 누르면 blog_detail로 들어가도록 구현. 인자로 post.pk를 줌
                <a href="{% url 'blog_detail' post.pk %}">{{ post.title }}</a>
            </li>
        {% endfor %}
    </ul>
    <p>{% url 'blog_list' %}</p>
    <p>{% url 'blog_detail' 1 %}</p>
</body>
</html>

db의 데이터 개수만큼 링크를 생성하는 코드이다.

# templates > blog > blog_detail.html

<!DOCTYPE html>
<html lang="ko">
<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>blogdetail</title>
</head>
<body>
    <h1>blogdetail</h1>
    <h2>{{ db.title }}</h2>
    <p>{{ db.contents }}</p>
    <p>{{ db.created_at }}</p>
    <p>{{ db.updated_at }}</p>
    # blog_list로 돌아가는 목록 하이퍼링크 생성
    <a href="{% url 'blog_list' %}">목록</a>
</body>
</html>

세부 페이지에서 목록이라는 링크를 클릭하면 원래의 blog_list 페이지로 돌아가게끔 하였다.

ORM

파이썬 문법을 통해 DB를 조작할 수 있는 편리한 기술(모델 클래스와 DB의 테이블을 자동으로 연관지어 주는 기술) 이다.

이번 예제에서는 간단한 CRUD 확인을 위하여 manage.py의 쉘을 사용한다.

쉘 접속

python manage.py shell

Read

데이터를 읽어오는 문법이다.

Post의 모든 객체 불러오기

>>> from blog.models import Post
>>> Post.objects.all()

pk순으로 정렬하기

>>> Post.objects.all().order_by('-pk')

-pk라고 하면 내림차순 정렬이다.

전체 객체의 개수 반환

>>> Post.objects.count()

get 메서드, filter 메서드

>>> q = Post.objects.get(id=1)
>>> q

get 메서드는 조건에 맞는 하나의 데이터를 조회한다. 데이터가 2개 이상이면 예외를 발생한다.

filter 메서드는 조건에 맞는 모든 데이터를 조회한다. 데이터가 없어도 예외를 발생시키지 않는다.

get 은 유일한 필드를 조회하는 데에 사용되며, filter 는 특정 조건에 맞는 모든 데이터를 조회하거나 데이터의 존재 여부를 확인하는 데에 사용한다.

>>> Post.objects.filter(title__contains='1')

연산자

데이터를 불러오는 조건으로 연산자를 활용할 수도 있다.

  • eq : 해당 조건과 같은지 판별
  • ne : not equal
  • lt : little(미만)
  • le : little or equal (<=)
  • gt : greater(초과)
  • ge : greater or equal (>=)
>>> Post.objects.filter(id__lt=3)

위와 같이 사용하면 id가 3 미만인 것만 필터링하여 가져온다.

Create

데이터를 생성하는 문법이다.

>>> q = Post.objects.create(title='c4', contents='c44')

createsave라는 문법이 필요 없지만, 글을 생성하고 수정하고 save를 안하는 경우가 있어 무조건 하는 것을 추천한다고 한다.

>>> q.save()

Delete

데이터를 삭제하는 문법이다.

>>> q = Post.objects.get(pk=3) 
>>> q.delete()
(1, {'blog.Post': 1})

detele 뒤에 출력된 문구는 삭제된 객체가 1개이며, 그 중 blog.Post 모델의 객체가 1개라는 것이다.

Update

데이터를 수정하는 문법이다.

>>> q = Post.objects.all()[0]
>>> q.title
'1'
>>> q.title = 'hello world1'
>>> q
<Post: 제목: hello world1, 생성시간: 2024-02-23 02:39:11, 수정시간: 2024-02-23 02:39:11>

q의 원래 제목은 1 이었지만, hello world1로 변경된 것을 볼 수 있다.

쉘이 아닌 직접 웹에 적용해보기

이를 통해 웹에서 게시물 CRUD를 UI와 함께 진행할 수 있다.

# blog > urls.py

from django.urls import path
from . import views

urlpatterns = [
    path("", views.blog_list, name="blog_list"),
    path("<int:pk>/", views.blog_detail, name="blog_detail"),
    path("create/<str:title>/", views.blog_create, name="blog_create"),
    path("delete/<int:pk>/", views.blog_delete, name="blog_delete"),
    path("test/", views.blog_test, name="test"),
]
# blog > views.py

from django.shortcuts import render, redirect
from .models import Post


def blog_list(request):
    blogs = Post.objects.all()
    context = {"db": blogs}
    return render(request, "blog/blog_list.html", context)


def blog_detail(request, pk):
    blog = Post.objects.get(pk=pk)
    context = {"db": blog}
    return render(request, "blog/blog_detail.html", context)


def blog_create(request, title):
    contents = f"hello world {title}"
    q = Post.objects.create(title=title, contents=contents)
    q.save()
    return redirect("blog_list")


def blog_delete(request, pk):
    q = Post.objects.get(pk=pk)
    q.delete()
    return redirect("blog_list")


def blog_test(request):
    return render(request, "blog/blog_test.html")
profile
익숙해지기 위해 기록합니다

0개의 댓글