[django] C.R.U.D 2 (1) 주인과 강아지

지난번 models.py에 이어서, views.py와 urlConf 까지 작성해서 django 전체를 완성해보자.

URLconf: 클라이언트로부터 들어온 요청을 분석 및 라우팅하는 모듈
VIEW: 클라이언트 요청 처리를 위해 필요한 로직을 구현하는 모듈
MODEL: DB 생성(테이블 생성, 맵핑) 모듈
DATABASE: raw data의 집합체


0
추가 settings: client 준비

우선, http 통신을 위해서 API test program인 postman을 다운받았다.
과제 가이드에서는 httpie를 다운받으라고 되어 있었는데, postman이 더 좋다는 멘토님 말 참고함.

brew update                           # Fetch latest version of homebrew and formula.
brew tap homebrew/cask                # Tap the Homebrew/Cask repository from Github using HTTPS.
brew search postman                   # Searches all known Casks for a partial or exact match.
brew info --cask postman              # Displays information about the given Cask
brew install --cask postman           # Install the given cask.
brew cleanup                          # Remove any older versions from the cellar.

1
초기셋팅

과제 디렉토리 생성 > 가상환경 설정 > 데이터베이스 설정 > github repo 생성
장고 설정 > settings.py 설정 완료 후 > git first commit > push (main)
그리고 각 과제는 별도의 branch에 생성하므로, branch를 만들고 프로젝트에 app을 추가해 git commit & push 완료 한다.

아래와 같이,
featuer/onwer branch에 checkout 한 상태에서 owners라는 app을 디렉토리에 추가하고, weanimal_db라는 데이터베이스를 만들어놓고 shell을 켰다.



그리고 migrate도 미리해서 DB와 연결이 잘 되었는지 확인하는 것이 좋다.
makemigrations 작업 없이도 가능한 이유는, django 자체에서 생성하는 테이블들이 존재하기 때문.

  • django_content_type: 프로젝트에 있는 app과 model 기록
  • django_migrations: migration 적용 기록
  • django_session: 세션(정보교환) 정보 기록

2
models.py 작성

models.py 작성 후, migrate 작업을 한다.

python manage.py makemigrations owners(app name)
python manage.py migrate 

그리고 shell에서 database import 하기

from app이름.models import Owner,Dog 

migrate가 중요한게, models.py/views.py 등 다 건드려놓고 migrate를 제대로 하지 않으면 오류가 뜬다.

3
views.py 작성

POST 작성할 때, 처음 작성했던 내용은 아래와 같았다.
그리고 postman을 통해 body를 보냈으나 바로 age는 null값이 될 수 없다고 에러 뜸.

class OwnersView(View):
    def post(self, request):
        data = json.loads(request.body)

        name = Owner.objects.create(name=data['name'])
        email = Owner.objects.create(email=data['email'])
        age = Owner.objects.create(age=data['age'])

        Owner.objects.create(
            name = name,
            email = email,
            age = age
        )

        return JsonResponse({"message":"created"}, status=201)
# Column 'age' cannot be null

처음엔 이것도 이유를 찾는답시고 database 지우고 다시 셋팅하고, migrate 다시 했으나 계속 같은 오류.

오류난 이유는, models.py에서 Owners를 정의할 때 name/email/age는 무조건 값이 들어가야 하도록 작성했다.

그러다 보니, views.py를 위와 같이 작성해 버리면 name=Onwer.objects.create(name['data'])에서 name만 create되고 나머지 값들은 null처리가 되기 때문에 에러가 뜨는 것. name=Onwer.objects.create(name['data']) 앞뒤로 print(1)print(2)를 작성해서 돌리면 1을 찍고 바로 에러 난다. 이렇게 에러를 찾는 방법도 있음을 배웠다.

아래와 같이 수정.

class OwnersView(View):
    def post(self, request):
        data = json.loads(request.body)

        Owner.objects.create(
            name = data['name'],
            email = data['email'],
            age = data['age']
        )

        return JsonResponse({"message":"created"}, status=201)

이 상태에서 다시 데이터 send 하면 아래와 같이 완료.

데이터베이스를 불러오면 아래와 같이 업데이트됨.


dogs테이블 데이터도 처리해줄 Dogsview 작성하고,
발생할 수 있는 error 3가지: KeyError, DoesNotExist, MultipleObjectReturned 까지 예외처리 추가했다.
shell에서 get()은 아래 특징을 갖기 때문임:

  • 반드시 해당 DB에 있어야 한다.
  • 1개만 return 한다.
  • return 형태는 객체다. (QuerySet이 아님)

(전쟁에서 진 장수는 용서해도 경계에 실패한 장수는 용서하지 않는다...)

#OwnerView
class OwnerView(View):
    def post(self,request):
        try:
            data = json.loads(request.body)
            Owner.objects.create(
                name  = data['name'],
                email = data['email'],
                age   = data['age']
            )
            return JsonResponse({'message':'success'},status=200)
        except KeyError:
            return JsonResponse({'error':'KEYERROR'},status=400)
            

#DogView
class DogView(View):
    def post(self,request):
        try: 
            data = json.loads(request.body)
            owner = Owner.objects.get(name=data['owner'])	
            Dog.objects.create(
                name  = data['name'],
                age   = data['age'],
                owner = owner.id	#Owner.object(1)의 id값 
            )
            return JsonResponse({"message":'created'},status=200)

        except KeyError:
            return JsonResponse({'error':'KEYERROR'},status=400)
        except Owner.DoesNotExist:
            return JsonResponse({'error':'specified owner does not exist'},status=404)
        except Owner.MultipleObjectsReturned:
            return JsonResponse({'error':'multiple objects returned'},status=400)

get메소드는 아래와 같이 작성. for문은 list comprehension으로 바꿨다.

#OwnerView 
class OwnerView(View):
    def get(self,request):
        result = [{
            'name'  : owner.name,
            'email' : owner.email,
            'age'   : owner.age,
            'dog_info' : [{
                'name' : dog.name,
                'age'  : dog.age
            } for dog in owner.dog_set.all()]} for owner in Owner.objects.all()]
            #dog name/age는 dog테이블로 역참조해서 갖고 온다 
            #Owner:Dog=1:N, 1-> N의 형태는 역참조임 
        
        return JsonResponse({'result':result},status=201)
 
 
#DogView
class DogView(View):
    def get(self,request):
        result = [{'name':dog.name,'age':dog.age,'host_name':dog.owner.name} for dog in Dog.objects.all()]
        #dog.owner.name: 해당 dog 데이터의 owner(owner_id)의 이름 
        
        return JsonResponse({"message":result},status=201)

urls.py는 아래와 같이 바꿔줬다.

#owners > urls.py
from django.urls import path
from owners.views import DogsView, OwnersView

urlpatterns = [
    path('/owners',OwnersView.as_view()),
    path('/dogs',DogsView.as_view())
]

참고 자료:
https://www.javanibble.com/how-to-install-postman-on-macos-using-homebrew/
https://stackoverflow.com/questions/36895063/why-is-django-migrations-table-in-all-databases
https://tech.toktokhan.dev/2021/06/16/django-session/
https://stackoverflow.com/a/20637325

좋은 웹페이지 즐겨찾기