Django C.R.U.D 연습

jinatra·2021년 8월 18일
0

Django

목록 보기
2/9
post-thumbnail

Django C.R.U.D 연습


C.R.U.D란 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인

  • Create (생성)
  • Read (읽기)
  • Update (갱신)
  • Delete (삭제)

를 뜻한다.
여기선 C, R을 한번 Review해보고자 한다.


1. Django Project 초기 세팅

기존에 작성하였던 글을 참조하여 아래와 같이 테스트용 프로젝트를 생성하였다.

test 가상환경 생성
django_project 프로젝트 생성
practice/pet 브랜치 생성
cats App 생성


2. MySQL DB Table 작성

주인 - 고양이 관계를 생성하여, 두세사람이 여러마리의 고양이를 가졌다고 가정한 후 해당 DB를 통해 아래 기능을 구현할 예정이다.

  • Create (생성) - POST 이용
  • Read (읽기) - GET 이용

3. Model 작성

어떠한 데이터가 들어갈 것인지 정했으므로, 데이터가 들어갈 Model을 생성하면 된다.

우리는 django_project 이름의 프로젝트를 만들었고, cats 라는 앱을 만들었다.
이제 cats 앱 안에 생성된 models.py 파일에 모델을 정의해주면 된다.

처음 models.py로 들어가보면 아래와 같다.

이제 모델을 아래와 같이 구현하면 된다.

# cats/models.py

from django.db import models

class Owner(models.Model):
    name    = models.CharField(max_length=45)
    email   = models.CharField(max_length=300)
    age     = models.IntegerField()

    class Meta:
        db_table = 'owners'

class Cat(models.Model):
    owner   = models.ForeignKey('Owner', on_delete=models.CASCADE)
    name    = models.CharField(max_length=45)
    age     = models.IntegerField()

    class Meta:
        db_table = 'cats'

이제 각 줄의 의미를 알아보자.

  • class Owner(models.Model): → 모델(객체)을 정의

    • class : 객체를 정의할것이라고 선언
    • Owner : 모델 이름
    • models : Owner이 장고 모델임을 알려줌
  • name = models.CharField(max_length=45) → 각 필드의 데이터타입 지정
    (당연하겠지만 aquery에 지정한 row대로 설정해주면 된다.)

  • owner = models.ForeignKey('Owner', on_delete=models.CASCADE) → 다른 모델의 FK인 경우 이와 같이 어떤 모델의 FK인지 선언해줘야 한다.
    (on_delete는 개체 삭제시 수행할 동작이고, models.CASCADE는 FK를 포함하는 행도 함께 삭제한다는 의미이다.)

  • class Meta: db_table : MySQL의 table 이름 지정

최종적으로는 아래와 같이 모델이 구현된다.

(위에 생성된 모델이랑 우리가 만들었던 아래의 Aquery 테이블을 비교해보자)

의문점

"Aquery에는 owner_id 라고 해줬는데 왜 모델에는 owner 라고만 적었냐?"
라고 생각할 수 있다.

해답은 꽤나 간단한데, 나중에 mySQL에서 FK같은 경우는 자기가 알아서 뒤에 _id를 붙여주기 때문이다.

완성 후 요청을 보내보면 아래와 같이 나온다.

(owner_id라고 써있는게 보인다!!)


3-1. models.py의 기능

models.py의 기능을 이해할 필요가 있다.
Django는 models.py를 통해 데이터에 접근하고 관리한다.

즉, Django에서 기본적으로 제공하는 db.sqlite3와 연동해서 models.py에서 정의한 models 클래스의 데이터들을 DB형태로 관리하게 된다.


4. 작성 모델의 DB 적용

이제 아래의 두가지 방법을 거쳐 모델을 database에 적용시켜야한다.

  1. makemigrations
  2. migrate

1. makemigrations

models.py에 python code를 이용하여 작성한 모델을 database에 적용하기 위해 migration 파일(설계도)을 만든다.

python manage.py makemigrations app이름

2. migrate

makemigration으로 생성한 migration 파일(설계도)을 database에 적용

python manage.py migrate

실제로 shell에서 코드를 치면 아래와 같이 적용된다.


5. View 작성 (POST를 이용하여 Create)

데이터가 들어갈 모델을 작성했으니 이제 View를 이용하면 된다.
이제 POST를 이용해서 데이터를 집어넣는 로직을 짜보자.

처음 views.py를 들어가면 아래와 같다.

이제 아래와 같이 구현하면 된다.

# cats/views.py

import json
from django.db.models.fields import EmailField

from django.shortcuts   import render
from django.http        import JsonResponse
from django.views       import View

from cats.models    import Owner, Cat

class OwnersView(View):
    def post(self, request):
        data    = json.loads(request.body)
        owner   = Owner.objects.create(
            name    = data['owner_name'],
            email   = data['email'],
            age     = data['owner_age']
        )
        return JsonResponse({'MESSAGE':'Owner Info Created!'}, status=201)

class CatsView(View):
    def post(self, request):
        data    = json.loads(request.body)
        owner   = Owner.objects.get(name=data['owner_name'])
        cat     = Cat.objects.create(
            owner   = owner,
            name    = data['cat_name'],
            age     = data['cat_age'],
        )
        return JsonResponse({'MESSAGE':'Cat Info Created!'}, status=201)

views.py 에서는 보통 파이썬 문법을 활용하여 여러 함수들을 생성하게 되며, 이 함수들을 이용하여 자신이 원하는 형태로 데이터를 처리한 뒤, 어떠한 html로 데이터를 보내게 되는 것이다.


5-1. Client 준비 (httpie 설치)

서버에 HTTP Request를 가능하게 해주는 httpie를 설치하면 자체적으로 확인이 가능하다.

brew install httpie


6. 앱의 urls.py 작성

view를 만들었으면 이제 클라이언트의 요청을 받아 적절한 view를 매핑해주는 urls.py를 작성하면 된다.

우리는 cats 앱을 만들었으므로, 해당 위치에 urls.py를 생성 해주자.

또는 아래와 같이 shell에서 바로 작성해주어도 무방하다.

touch urls.py    # urls.py 생성
vi urls.py       # urls.py로 이동

이제 urls.py에 아래와 같이 입력해주자.

# cats/urls.py

from django.urls    import path
from cats.views     import OwnersView, CatsView

urlpatterns = [
    path('owners', OwnersView.as_view()),
    path('cats', CatsView.as_view()),
]

우리는 위에서 두개의 view class를 정의했다.
각각의 view class에 대해, 클라이언트가 입력한 정보를 어떻게 처리하여 보여줄(view)것인가를 urls.py가 도와주는 개념이다.
path에 있는 owners, cats를 address/main_url_path 뒤에 추가하게 되면 views.py에서 정의했던 각각의 class와 연결이 된다.


7. 메인 urls.py 작성

이제 클라이언트로부터 제일 처음 요청을 받기 위해 메인 urls.py를 작성해주면 된다.

처음 모양은 아래와 같다.

이제 아래와 같이 추가하면 된다.

# django_training/urls.py

from django.urls import path, include

urlpatterns = [
    path('pets/', include('cats.urls')),
]

VSCode로 보면,

이제 domain/pets/owners 혹은 domain/pets/cats와 같이 url이 연결된다.


8. django 서버에 요청해보기

앞서 httpie를 설치하였다.
이제 위에 작성한 POST를 이용하여 서버에 데이터를 Create해보자!

먼저 Owner 데이터를 입력해보자.
views.py에서 정의한 json 데이터 형식의 key와 value를 아래와 같이 임의로 지정해줘봤다.
(key라고 하는게 맞는지 모르겠다. python의 딕셔너리 형식과 비슷해서 일단 이렇게 생각하고 있다.)

http -v POST 127.0.0.1:8000/pets/owners owner_name='김장고' email='django@django.com' owner_age='21'

위를 보면 알겠지만, mail URL인 pets 뒤에 앱의 url인 owners로 간다고 했고,
위에서 언급했던것처럼 그럼 우리가 views.py에서 선언했던 Owners Class를 이용하는 것이다.

테이블이 생성되지 않았다고 한다.
여기엔 언급되지 않았지만 views.py에서 객체를 import하는 과정에서 오타가 있어서 수정을 했는데, 그래서 migrate을 다시 해야했던것 같다.

그래서 migrate을 다시 진행했다.

근데 아니란다.
내가 migrate을 한 다음 db_table의 이름을 바꿨는데 그게 적용 안돼서 그랬던거 같다.

아무튼 이제 다시 제대로 위와 같이 데이러를 Create 해보자.

잘 됐다. (이게 뭐라고 눈물이 난다.)

그럼 이제 고양이 정보도 잘 create 되는지 해보자.

잘 된다.

사실 여기에는 우여곡절이 있었는데 오류 코드는 아래와 같다.

# cats/views.py

class CatsView(View):
    def post(self, request):
        data    = json.loads(request.body)
        cat     = Cat.objects.create(
            owner   = Owner.objects.get(name=data['owner_name']),
            name    = data['cat_name'],
            age     = data['cat_age'],
        )
        return JsonResponse({'MESSAGE':'Cat Info Created!'}, status=201)

참 멍청했다. 아래 aquery 테이블을 보자

FK인 owner_id를 설정해줘야 하는데, 그걸 바보같이 Cat 객체 안에서 지정을 해준 것이다.

당연히 owner_id는 바깥으로 빼서 지정해줘야하고,
cat 내부의 owner은 그냥 변수로 같다고만 해줘도 된다.

# cats/views.py

class CatsView(View):
    def post(self, request):
        data    = json.loads(request.body)
        owner   = Owner.objects.get(name=data['owner_name'])
        cat     = Cat.objects.create(
            owner   = owner,
            name    = data['cat_name'],
            age     = data['cat_age'],
        )
        return JsonResponse({'MESSAGE':'Cat Info Created!'}, status=201)

9. View 작성 (Get을 이용하여 Read)

아래와 같이 DB를 만들었다.
이제 아래 데이터들을 불러오는 get 함수를 만들어볼 것이다.

아래와 같이 만들어보자.

cats/views.py

import json
from typing import AsyncGenerator
from django.db.models.fields import EmailField

from django.shortcuts   import render
from django.http        import JsonResponse
from django.views       import View

from cats.models    import Owner, Cat

class OwnersView(View):
    # POST
    def post(self, request):
        data    = json.loads(request.body)
        owner   = Owner.objects.create(
            name    = data['owner_name'],
            email   = data['email'],
            age     = data['owner_age']
        )
        return JsonResponse({'MESSAGE':'Owner Info Created!'}, status=201)

    # GET
    def get(self, request):
        owners  = Owner.objects.all()
        results = []
        for owner in owners:
            results.append(
                {
                    "Owner\'s name"  : owner.name,
                    "e-mail address" : owner.email,
                    'Owner\'s age'   : owner.age,
                }
            )
        return JsonResponse({'Result!':results}, status=200)


class CatsView(View):
    # POST
    def post(self, request):
        data    = json.loads(request.body)
        owner   = Owner.objects.get(name=data['owner_name'])
        cat     = Cat.objects.create(
            owner   = owner,
            name    = data['cat_name'],
            age     = data['cat_age'],
        )
        return JsonResponse({'MESSAGE':'Cat Info Created!'}, status=201)

    # GET
    def get(self,request):
        cats = Cat.objects.all()
        results = []
        for cat in cats:
            results.append(
                {
                    'Cat\'s name' : cat.name,
                    'Cat\'s age'  : cat.age,
                    'Owner\'s name' : owner.name
                }
            )
        return JsonResponse({'Result!':results}, status=200)

Owner 정보를 GET 해보자

http -v GET 127.0.0.1:8000/pets/owners

잘 나왔다.

이제 Cat 정보를 불러보자.

http -v GET 127.0.0.1:8000/pets/cats

에러가 났다.

에러를 알아보기 전에 Owner 정보는 잘 나왔으니 어떻게 저렇게 짰나 생각을 해보자.

  1. cats라는 변수를 지정하고, Cat class의 모든 객체를 불러온다.
  2. 빈 list인 results 생성
  3. for문을 만들고, list안에 dictionary 형식으로 정보를 불러온다. (어떤 정보냐면 아래의 정보다.)

이런식으로 진행이 된다고 보면 된다.
기본적으로 for문으로다가 하나씩 돌려서 정보를 뽑아내는 형식이다.

근데 NameError가 떴다.
왜이럴까?
당연하다.
CatsView class에서, for문에 cat에 대해서만 돌렸는데, 갑자기 owner이 나와버리니 owner가 정의되지 않았다고 뜨는 것이다.

아래와 같이 고쳐보자.

잘 불러져왔다!!!!





Take Away

ForeignKey의 지정

위에서는 동명이인의 경우를 생각하지 않았지만, 동명이인이 존재하는 경우 위 예시처럼 하면 안된다.
만약 위 정보로만 하게된다면, 이름이 아닌 이메일 이름으로 구분을 해야할 듯 하다.
이렇듯 다뤄야하는 정보가 많아지고, 생각해야하는 관계가 많아지면 정보간의 관계를 잘 조율하여야할 듯 하다


역참조

위 관계는 cat은 owner를 참조하고 있다.
그래서, cat에서 owner를 불러오는것은 가능한데 역으로 owner가 cat 정보를 불러오는(역참조)는 위 방법으론 불가능하다.
이제 역참조가 어떻게 가능한지를 알아봐야겠다.





참고
https://tutorial.djangogirls.org/ko/django_models/
https://076923.github.io/posts/Python-Django-11/
https://livetodaykono.tistory.com/42
https://velog.io/@magnoliarfsit/ReDjango-3.-GET-POST-메소드-차이점-및-api-설계
https://opentutorials.org/module/4034/24661

profile
으악

0개의 댓글