TIL65. Django : SQL과 Django ORM의 관계

18653 단어 ORMORM

📌 이 포스팅에서는 Django의 ORM 문법과 SQL문법에 대해 비교 정리하였습니다.



🌈 SQL과 Django ORM의 관계

🔥 SELECT 구문

🔥 WHERE 구문

🔥 CREATE 구문

🔥 UDATE 구문

🔥 DELETE 구문



1. SELECT 구문

🤔 모든 row를 가져올 때, all()

✔️ Person이란 table에서 모든 column을 기준으로 모든 row 가져올 때 SQL문법에서는 아래와 같은 문법을 사용한다.

mysql> SELECT * FROM Person;

✔️ ORM으로 사용하면 아래와 같다. 해당 table 모든 row를 가져왔기 때문에 for문 사용하여 객체를 1개씩 순회 가능하다.

all_data = Person.objects.all()
for data in all_data:
    print(data.name)
    print(data.email)
    print(data.age)

🤔 특정 row만 가져올 때, only()

✔️ 모든 row에 대해서 특정 column만 조회하고 싶다면, SQL문법에서 * 대신 해당 column을 지정해준다.

mysql> SELECT name, age FROM Person;

✔️ ORM으로 모든 row에 대해서 특정 column만 조회하고 싶다면, only를 사용합니다.

Person.objects.only('name', 'age')

🤔 지정된 column들의 중복을 제거한 row만 필요할 때, distinct()

✔️ column을 지정하여 중복된 값을 제외시킨 row를 가져올 때는 DISTINCT를 사용합니다.
✔️ 아래 명령은 name과 age의 컬럼의 모든 row들 중 중복을 제외한 row를 읽어드립니다.

mysql > SELECT DISTINCT name, age FROM Person;

✔️ ORM으로 구현하면 아래와 같습니다. 값들의 중복을 체크하기 때문에 values와 함께 사용합니다.

Person.objects.values('name', 'age').distinct()

🤔 row의 양을 제한할 땐 슬라이싱

✔️ 가져올 row의 갯수는 LIMIT을 통해 제한할 수 있다.

mysql> SELECT * FROM Person LIMIT 10;

✔️ ORM으로 row의 수를 제한하려면 슬라이싱 사용한다.

limit_data = Person.objects.all()[:10] 

✔️ SQL에서 시작점을 지정할 때는 OFFSET을 사용한다. 5로 지정되면 6번째 row부터 10개의 row의 읽어드린다.

mysql > SELECT * FROM Person OFFSET 5 LIMIT 10;

✔️ ORM으로 제어하면 슬라이싱을 사용하면 된다.

limit_data = Person.objects.all()[5:10] 


2. WHERE 구문

🤔 조건에 해당되는 row를 가져올 때,, filter()

✔️ SQL의 WHERE은 조건을 걸어 해당하는 조건의 값들만 걸러낼 수 있다.
✔️ 비교연산자를 통해 어떤 기준보다 크거나 작은, 또는 기준이 아닌 값들만도 필터할 수 있다.

mysql > SELECT * FROM Person WHERE id = 1; 👈 id값이 1인 row
mysql > SELECT * FROM Person WHERE age > 18; 👈 age값이 18보다 큰 row들
mysql > SELECT * FROM Person WHERE age <= 18; 👈 age값이 18보다 작거나 같은 row들
mysql > SELECT * FROM Person WHERE age != 18; 👈 age값이 18이 아닌 row들

✔️ ORM으로는 언더바 2개(__)를 통해 비교연산자와 같은 기능을 사용할 수 있다.

Person.objects.filter(age__gt=18) 👈 age값이 18보다 큰 row들
Person.objects.filter(age__gte=18) 👈 age값이 18과 크거나 같은 row들
Person.objects.filter(age__lt=18) 👈 age값이 18보다 작은 row들
Person.objects.filter(age__lte=18) 👈 age값이 18보다 작거나 같은 row들
Person.objects.filter(age!=18) 👈 age값이 18이 아닌 row들

🤔 범위를 이용해 WHERE 다룰 땐, BETWWEN ~ AND

✔️ SQL에서 조건을 걸어 만족하는 row만 가져올 때는 BETWEEN ~ AND를 사용한다.

mysql > SELECT * FROM Person WHERE age BETWEEN 10 AND 20;

✔️ ORM에서는 column에 `__range를 걸어 range 함수처럼 사용이 가능하다.

Person.objects.filter(age__range=(10, 20))

🤔 해당 값을 포함하는 속성 값을 가진 row들을 가져올 때,

✔️ SQL에서 like 구문을 이용하면, 속성의 값이 어떤 조건과 해당하는 row들만 제한하여 가져올 수 있다.
✔️ "%"는 글자수를 정해주지 않을 때 사용하고, "_"는 글자 수를 정할 때 사용한다.
✔️ 또한 LIKE 절은 기본적으로 case-insensitive하다. 즉, 대소문자를 구별하지 않는다.
✔️ 따라서 대소문자를 구분하고 싶다면 "biranry"를 추가한다.

mysql > SELECT * FROM Person WHERE name like '%A%'; 👈 name값이 a 또는 A를 포함한 row들
mysql > SELECT * FROM Person WHERE name like 'A%'; 👈 name값이 a 또는 A로 시작하는 row들
mysql > SELECT * FROM Person WHERE name like binary'%A'; 👈 name값이 A로 끝나는 row들

✔️ ORM에서는 특정 값을 기준으로 해당 속성에 포함여부를 가지고 필러링을 할 때 아래와 같은 옵션을 사용한다.
✔️ contains과 icontains 해당 값을 포함하는 row를 필터한다. 이 둘의 차이점은 icontains의 경우 대소문자를 구분하지 않는다는 것이다.
✔️ 즉, ORM에서 기본으로 'case-sensitive'하다. 대소문자를 구분하기 때문에 대소문자를 구분하지 않고 조건을 적용시키고 싶다면 i를 붙인다.

Person.objects.filter(name__icontains='A') 👈 name필드의 값이 a 또는 A를 포함하는
Person.objects.filter(name__contains='A') 👈 name필드의 값이 A를 포함하는
Person.objects.filter(name__istartswith='A') 👈 name필드의 값이 a 또는 A로 시작하는
Person.objects.filter(name__startswith='A') 👈 name필드의 값이 A로 시작하는 
Person.objects.filter(name__iendswith='A') 👈 name필드의 값이 a또는 A로 끝나는
Person.objects.filter(name__endswith='A') 👈 name필드의 값이 A로 끝나는

🤔 해당 값과 일치하는 속성 값을 가진 row들만 가져올 때,

✔️ 여러개 값을 주어, 그 값과 일치하는 속성값을 가진 row들을 반환할 때는 IN 구문을 사용한다.

mysql > SELECT * FROM Person WHERE score in ('A', 'B');

✔️ ORM에서도 언더스코어와 in을 사용해서 filter할 수 있다.

Person.objects.filter(score__in=['A', 'B'])

🤔 AND, OR, NOT 을 ORM에서 사용하고 싶을 때,

✔️ SQL에서 여러개의 조건을 걸어줄 때는 AND, OR, NOT을 사용한다.

mysql > SELECT * FROM Person WHERE gender='male' AND age > 25
mysql > SELECT * FROM Person WHERE gender='male' OR age > 25;
mysql > SELECT * FROM Person WHERE NOT gender='male';

✔️ ORM에서 이를 사용하려면 아래와 같다. 콤마(,)는 AND, |는 OR, exclude는 NOT을 의미한다.

from django.db.models import Q
Person.objects.filter(gender='male', age__gt=25)
Person.objects.filter(Q(gender='male') | Q(age__gt=25))
Person.objects.exclude(gender='male')

🤔 정렬해서 가져오고 싶을 때, order_by()

✔️ ORDER BY를 통해 정렬하여 가져올 수 있고, 기본이 오름차순이다.
✔️ 내림차순으로 정렬하고 싶다면 DESC를 붙인다.

mysql > SELECT * FROM Person ORDER BY age;
mysql > SELECT * FROM Person ORDER BY age DESC;

✔️ ORM에서는 order_by를 사용한다. 기본이 오름차순이고 내림차순을 원한다면 "-"를 필드명 앞에 붙인다.

Person.objects.order_by('age')
Person.objects.order_by('-age')


3. CREATE 구문

🤔 DB에 데이터를 생성할 때는 create()

✔️ SQL에서는 INTO를 통해 데이터를 생성한다.

mysql >INSERT INTO Person VALUES ('Jack', '23', 'male');

✔️ ORM을 이용할 경우, 객체에 create를 사용해 필드에 값을 매핑시켜준다.

Person.objects.create(name='jack', age=23, gender='male)


4. UPDATE 구문

🤔 1개의 row를 수정할 때,

✔️ id값이 1인 row의 age값을 20으로 수정하고자한다면 아래와 같은 SQL문을 사용한다.

mysql > UPDATE Person SET age = 20 WHERE id = 1;

✔️ ORM의 경우, get을 통해 해당 객체를 가져온 뒤, 객체의 필드값에 원하는 값을 넣고 저장한다.

person = Person.objects.get(id=1)
person.age = 20
person.save()

🤔 여러개의 row를 수정할 때,

✔️ SQL의 경우 WHERE 구문으로 특정 데이터를 지정하지 않으면 테이블의 모든 필드에 적용시킬 수 있다.

mysql > UPDATE Person SET age = age * 1.5;

✔️ ORM의 경우 F 객체를 가져와 모든 age값에 수정을 적용시킬 수 있다.
✔️ F 객체를 사용하지 않는다면, 모든 객체를 가져와 for문을 돌리며 수정해야 한다.

from django.db.models import F
Person.objects.update(age=F('age')*1.5)


5. DELETE 구문

🤔 테이블의 모든 rows를 삭제할 때,

✔️ DELETE를 통해 해당 Table을 지정하면 모두 데이터가 삭제된다.

mysql > DELETE FROM Person;

✔️ all()을 통해 모든 객체를 가져온 뒤, delete로 지워준다.

Person.objects.all().delete()

🤔 특정 row들만 삭제할 때,

✔️ WHERE 구문을 통해 해당 조건에 만족하는 row를 지우는 방법은 아래와 같다.

mysql > DELETE FROM Person WHERE age < 10;

✔️ ORM에서도 filer나 get을 통해 특정 row들을 찾은 후, delete()를 통해 삭제할 수 있다.

Person.objects.filter(age__lt=10).delete()

좋은 웹페이지 즐겨찾기