[Django] __ 는 어떻게 사용되는가

happy tiger·2022년 7월 26일
1

Django

목록 보기
1/3
post-thumbnail
post-custom-banner

django의 ORM을 사용하면서 __를 접하게 되었다.
정리를 하지 않고 계속 마주치니 __가 어떤 기능을 하는 것인지 매우 헷갈렸다. 나와 같은 상황인 개발자들이 많을 것이라 생각되어, 한 번 제대로 정리하고 넘어가고자 한다.

1. 테이블을 이동하는 수단

django ORM의 장점 중 하나는 서로 다른 테이블을 쉽게 넘어다닐 수 있다는 것이다.
테이블을 쉽게 넘어다닐 수 있게 하는 수단이 바로 __이다.

아래 예시로 이해해보자.
아래는 models.py에 있는 class들이다.

class Category(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        db_table = 'categories'

class SubCategory(models.Model):
    name     = models.CharField(max_length=100)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)

    class Meta:
        db_table = 'sub_categories'

class Product(models.Model):
    name         = models.CharField(max_length=100)
    stock        = models.IntegerField()
    sub_category = mfodels.ForeignKey('SubCategory', on_delete=models.CASCADE)

    class Meta:
        db_table = 'products'

위의 코드를 보면 Product가 SubCategory를 참조하고, SubCategory가 Category를 참조하는 것을 볼 수 있다.
하지만 django의 ORM에선, 참조와 역참조는 중요하지 않다. 중요한 것은 두 테이블이 서로 연결되어 있다는 것이다. 두 테이블 중 하나의 column이 참조를 위한 column이라면 두 테이블은 서로 연결되어, __를 이용해 서로의 테이블을 호출을 할 수 있다.

category의 id가 4인 product를 알고싶다면, __를 어떻게 사용하면 될까?
Product 테이블은 SubCategory와 연결되어 있고, SubCategory 테이블은 Category테이블과 연결되어 있다.
고로, 아래의 코드처럼 Product 테이블은 SubCategory 테이블을 __를 이용하여 호출할 수 있고, SubCategory 테이블은 Category 테이블을 __를 이용하여 호출할 수 있다.

>>> Product.objects.filter(subcategory__category__id = 4)
 <QuerySet [<Product: Product object (10)>, <Product: Product object (15)>,
 	 		<Product: Product object (16)>, <Product: Product object (17)>, 
            <Product: Product object (19)>]>

어떤 model에서 자신을 foreign key로 가지고 있는 모델에 접근하기위해선 _set을 붙여주면 된다.

b = Category.objects.filter(id=1)
b.subcategory_set.all()

2. 조건을 표현하는 수단

조건을 통해 데이터를 조회할 때 또한, __가 사용된다.
필드명__조건 = 조건값 을 filter 의 인자로 넘겨주어 조건에 부합되는 데이터를 return 받아 조회할 수 있다.

조건들과 함께 예시로 이해해보자.

필드명__lt = 조건값 : 필드명 < 조건값

Product.objects.filter(is_published__lt = date(1961,1,1))
필드명__lte = 조건값 : 필드명 <= 조건값

필드명__gt = 조건값 : 필드명 < 조건값

필드명__gte = 조건값 : 필드명 < 조건값

예시는 전체적으로 비슷하다고 생각되어 첫번째 에서만 기재하였다.
각 알파벳은 의미하는 함축어가 존재하는데, l 은 less 를 g는 greater 를t 는 than 을 e 는 equal 을 의미한다.

# 문자열 필드
필드명__startswith
Post.objects.filter(title__startswich="Django")

필드명__startswith = "Django" 을 통해 'Django'로 시작하는 객체를 모두 가져와 반환한다.

필드명__endswith

필드명__endswith = 조건값 을 통해 조건값으로 끝나는 데이터를 모두 가져온다.

필드명__contains

필드명__contains = 조건값 을 통해 조건값이 포함되는 데이터를 모두 가져온다.

필드명__istartswith

필드명__istartswith = 조건값 , startswith 와 동일하지만 대소문자를 구분하지 않는다.

필드명__iendswith

필드명__iendswith = 조건값 , endswith 와 동일하지만 대소문자를 구분하지 않는다.

필드명__icontains

필드명__icontains = 조건값, contains 와 동일하지만 대소문자를 구분하지 않는다.

필드명__in = iterable 객체

Product.objects.filter(id__in=[1, 3, 4])

iterable 객체에 해당 필드가 존재하는 데이터를 모두 반환한다.
즉, Product의 id가 1 또는 3 또는 4 인 객체들을 리턴한다.

1 + 2 를 해보자

category의 id가 3 또는 4인 Product 객체들을 모두 반환하기 위해선 어떻게 해야할까?
category에 접근하기 위해서 __를 이용하여 Product에서 SubCategory에 접근하고, SubCategory에서 Category에 접근하고, Category에서 id를 접근한다.
그리고 그 id가 3 또는 4 여야한다는 조건이 존재하기에 __in을 이용하여 조건을 붙여준다. 그렇게 작성한 코드가 바로 아래 코드이다.

>>> Product.objects.filter(sub_category__category_id__in= [3,4])
<QuerySet [<Product: Product object (10)>, 
		   <Product: Product object (15)>, <Product: Product object (16)>]>
profile
호기심·끈기·성장·발전·행복·협력 ٩(๑•̀ㅂ•́)و
post-custom-banner

0개의 댓글