반응형
[Django] Performing raw SQL queries : SQL 쿼리 맵핑
Django는 원시 SQL 쿼리를 수행하는 두 가지 방법을 제공한다 :
1. Manager.raw ()를 사용하여 원시 쿼리(raw queries)를 수행하고 모델 인스턴스를 반환.
2. 모델 레이어를 완전히 피하고 사용자 정의 SQL을 직접 실행.
*raw SQL을 사용할 때마다 조심해야한다. 사용할 때마다 SQL Injection 공격으로 부터 보호하기 위해 params을 사용하여 사용자가 제어할 수 있는 파라메터를 벗어나도록 해야한다. SQL Injection 보호에 대해 자세히 읽어 보라.
Performing raw queries 원시 쿼리 실행
raw() 매니저 메소드는 모델 인스턴스를 반환하는 원시 SQL를 사용하는데 사용한다.
Manager.raw(raw_query, params=None, translations=None)
이 메소드는 원시 SQL쿼리를 실행하고, django.db.models.query.RawQuerySet 인스턴스를 반환한다. 이 RawQuerySey 인스턴스는 일반 쿼리셋(QuerySet)처럼 반복해 객체 인스턴스를 제공할 수 있다.
예를 통해 가장 잘 설명할 수 있다. 다음의 모델을 가지고 있다고 가정해보자.
class Person(models.Model): first_name = models.CharField(...) last_name = models.CharField(...) birth_date = models.DateField(...)
다음과 같이 사용자 정의 SQL 를 실행할 수 있다.
>>> for p in Person.objects.raw('SELECT * FROM myapp_person'): ... print(p) John Smith Jane Jones
물론, 이 예제는 매우 흥미롭지 않다. 이것은 Person.objects.all()를 실행한 것과 정확히 같다. 그러나, raw()는 매우 강력한 다른 옵션이 많이 있다.
*raw()에 전달된 SQL문에 대한 검사를 하지 않는다. Django는 이 명령문이 테이터베이스로부터 일련의 행을 반환할 것이라고 예측하지만, 아무것도 하지 않는다. 만약 쿼리가 행을 반환하지 않으면, 오류가 발생될 것이다.
Mapping query fields to model fields 모델 필드에 쿼리 필드 맵핑
raw()는 자동으로 쿼리의 필드를 모델의 필드에 맵핑한다.
쿼리에서 필드의 순서는 중요하지 않다. 다시 말해, 다음 두 쿼리는 동일하게 작동된다.
# 01 Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person') # 02 Person.objects.raw('SELECT last_name, birth_date, first_name, id FROM myapp_person’)
매칭은 이름으로 된다. 즉, SQL의 AS를 사용하여 쿼리의 필드를 모델 필드에 맵핑할 수 있다. 그래서 만약 Person데이터가 있는 다른 테이블을 갖고 있다면, Person 인스턴스로 손쉽게 맵핑할 수 있다.
Person.objects.raw('''SELECT first AS first_name, last AS last_name, bd AS birth_date, pk AS id, FROM some_other_table''')
이름이 일치하는 한 모델 인스턴스가 올바르게 작성된다.
또한, raw()에 translations 인자를 사용하여 쿼리의 필드를 모델 필드에 맵핑할 수 있다. 이 translations 딕셔너리는 모델 필드 이름에 쿼리 필드 이름을 맵핑한다. 예를 들어, 앞의 쿼리는 다음과 같이 작성할 수도 있다.
name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
Index lookups 인덱스 조회
raw()는 인덱싱을 지원하기 때문에 첫번째 결과만 원할 경우 다음과 같이 쓸수 있다.
first_person = Person.objects.raw('SELECT * FROM myapp_person')[0]
그러나, 인덱싱과 슬라이싱은 데이터베이스 레벨에서 실행되지 않는다. 만약 데이터베이스에 많은 수의 Person 객체(object)를 갖고 있다면, SQL레벨에서 쿼리를 제한하는 것이 좀더 효율 적이다.
first_person = Person.objects.raw('SELECT * FROM myapp_person LIMIT 1')[0]
반응형
'Python > Django' 카테고리의 다른 글
[Django] 사용자 인증 시스템 (2) (0) | 2019.01.23 |
---|---|
[Django] 데이터베이스에 초기(initial) 데이터 입력방법 (0) | 2019.01.22 |
[Django] Custom template tags and filters 사용자 정의 템플릿 태그(1) (0) | 2019.01.19 |
[Django] context_processors 콘텍스트 프로세서 (0) | 2019.01.16 |
[Python][Django] HttpRequest 객체 정보 (0) | 2019.01.12 |