TIL 44. django : QuerySet과 ORM, Model

7024 단어 djangoORMTILORM

wecode의 django crud 커리큘럼중에서 배운 점을 기록합니다. 이 글은 django공식문서를 토대로 썼습니다.

QuerySet API

No database activity actually occurs until you do something to evaluate the queryset.

QuerySet API 없이는 django에서 데이터베이스의 데이터들을 바꾸거나, 읽을 수 없다.

iteration

A QuerySet is iterable, and it executes its database query the first time you iterate over it.

for i in MyModel.objects.all():
	print(i.my_attribute)

QuerySet은 바로 리스트로써 다룰수는 없지만, iterable하기 때문에 반복문을 이용해서 요소들을 갖고 놀 수 있다.

Slicing

a QuerySet can be sliced, using Python’s array-slicing syntax. Slicing an unevaluated QuerySet usually returns another unevaluated QuerySet, but Django will execute the database query if you use the “step” parameter of slice syntax, and will return a list.

파이썬의 장점인 slicing을 QuerySet에서도 쓸 수 있다. 똑같이 리스트를 반환한다.

owners[0:len(owners)]
# [<Owner: 강형욱>, <Owner: 뚱이>, <Owner: 홍길동>, <Owner: john>]

슬라이싱의 간격도 정할 수 있다.

QuerySet 슬라이싱의 반환값은 리스트이다.

len 함수

QuerySet slicing은 -1처럼 음수 인덱싱이 안된다. 그래서 맨 끝의 index를 알려면 len함수를 쓴다.

count 메서드

SQL언어로 count가 len보다 더 빠르기 때문에, 단순히 길이만 구하는거라면 count함수가 더 좋다.

repr

A QuerySet is evaluated when you call repr() on it. This is for convenience in the Python interactive interpreter, so you can immediately see your results when using the API interactively.

list

list함수를 이용해서 QuerySet을 list타입으로 변환할 수 있다. 어떨 때 쓰는지는 모르겠다.

그래서?

파이썬 QuerySet을 다루려면, 보통 .문법으로 딕셔너리의 요소처럼 접근해야 한다.

처음에는, "그냥 QuerySet을 곧바로 리스트로 만들거나 JSON화시키면 되지 않나?"라고 생각했다. 그러나 그런 방법은 없었다..모듈이 있다고는 하는데 당분간 다루게 될 것 같지는 않다.

추가적으로, 반복문은 list comprehension을 이용해서 짧고 빠르게 코드를 짤 수 있다.

일대다 관계 구현

Foreign Key

한 쪽에서 다른 테이블을 참조하는 관계를 만들려면, django.models.ForeignKey를 사용한다.


class MyModel(models.Model):
	parent = models.ForeignKey("Parent")

이걸로 데이터베이스 테이블엔 foriegn key가 생긴다.

정참조와 역참조

일대다관계를 주종관계로 보면, 주인쪽에서는 역참조를 하고 종쪽에서는 정참조를 하게 된다. 정참조는 child.parent.name형태이고, 역참조는 parent.child_set.name형태다. _set이 붙은 인스턴스 명은 django가 자동적으로 만드는 manager객체이다.

manager이란, 간단히 얘기해서 데이터베이스에 대해서 관리자의 역할을 하는 ORM관련 객체다.

정참조의 manager은 forward_many_to_one_manager라는 이름을 갖고 있다.

역참조 manager은 reverse_many_to_one_manager라는 이름을 갖고 있다.

related_name

related_name파라미터에 인자값을 주면, 역참조할 때 그 이름대로 django 안에서 부를 수 있다. 이런 편리함 외에도, 한 쪽에서 다른쪽으로 여러 ForeignKey를 설정하는 경우에 related_name은 필수적이다.

항공과 지역이 일대다관계로 있다고 생각해보면, 출발지, 경유지, 도착지로 나눌 수 있다. 그러면 한 테이블에서 ForeignKey를 3개 줄텐데, 이러면 항공쪽에서 역참조 할 때 문제가 생긴다. ForeignKey가 겹친다는 것!

다대다 관계 구현

중간테이블 생성

ikea를 모델링할 때 만들었던 중간테이블. 각각의 테이블은 ForeignKey가 필요없지만, 중간테이블에서 각각의 테이블을 ForeignKey로 만들어줘야 한다.

ManyToManyField

ManyToManyField는 다대다 관계를 만드는 필드이름이다.

class Actor(models.Model):
	blahblah

class Movie(models.Model):
    actors = models.ManyToManyField(Actor)

재밌는건, 한 쪽에서만 관계성을 정의해줘도 된다는 것이다. 여기선 Movie쪽에서만 다대다관계를 정의했지만, 실제로 migration을 하면 서로의 중간테이블이 생긴다. 그러면 다른 쪽에서는 상대 instance를 model_set의 형태로 역참조할 수 있게 된다. Movie쪽에서는 그냥 actors라고 참조하면 된다.

add와 remove

다대다 관계의 두 인스턴스를 서로 추가해주려면, manager.add(<상대 instance>)를 쓴다.

반대로 삭제하려면 remove를 쓴다.

서로에 대한 참조

재밌는건 두 쪽 다 forward_many_to_many_manager라는 이름을 갖고 있다는 것이다. ManyToManyField를 호출한 건 둘 중 한쪽뿐인데, 두쪽에서 모두 정참조를 할 수 있다는 것.

related_name

ForeignKey를 쓸 때와 마찬가지로, 역참조를 할 때 _set이 붙은 이름이 아닌 내가 설정한 이름으로 할 수 있다.

through

중간 테이블에서 단순히 다대다관계를 나타내는 것 뿐만 아니라 다른 column을 필요로 할 때, 중간 테이블을 만들어야 한다.

그럴 때 쓰이는 게 through 파라미터이다. 중간테이블을 인자값으로 넣어주면 된다.

생각과 질문

  1. 한 프로젝트에는 데이터베이스가 하나! 실수로 앱마다 다른 데이터베이스를 연결했더니 매번 데이터베이스 세팅을 바꿔줘야 하는 일이 생겼다. 하나의 서버는 하나의 데이터베이스와 연결된다. 따라서 앱이 몇개가 있든간에 왠만하면 프로젝트당 하나의 데이터베이스만 연결해야 한다.
  2. repr?
  3. list comprehension이란??
  4. ForeignKey를 여러개 쓰는 경우를 보고 싶다.
  5. QuerySet이 django개발에서 정말 중요한 듯.

좋은 웹페이지 즐겨찾기