티스토리 뷰

728x90
반응형

Django에서 모델을 다룰 때, Python의 매직 메서드를 활용하면 보다 직관적이고 깔끔한 코드를 작성할 수 있습니다.

매직 메서드는 __ (언더스코어 두 개)로 시작하고 끝나는 특수한 메서드로, 특정한 동작을 수행할 때 자동으로 호출됩니다.

이번 글에서는 Django에서 자주 활용하는 매직 메서드에 대해 알아보고, 예제 코드와 함께 그 활용 방법을 살펴보겠습니다.


매직 메서드는 Python의 객체지향 프로그램  OOP 기능

매직 메서드는 Django의 고유 기능이 아니라 Python의 객체지향 프로그래밍(OOP)에서 제공하는 기능입니다. Python에서는 객체가 특정한 연산이나 동작을 수행할 때 매직 메서드를 자동으로 호출하도록 설계되어 있습니다. Django는 이를 활용하여 모델과 ORM을 보다 편리하게 사용할 수 있도록 하고 있습니다.

예를 들어, __str__() 매직 메서드는 객체를 문자열로 변환해야 할 때 자동으로 호출됩니다. Django의 models.Model 클래스를 상속한 모델에서도 __str__()을 오버라이딩하면, 해당 객체가 문자열로 변환될 때 이 메서드가 자동으로 실행됩니다.


매직 메서드는 왜 호출하지 않아도 동작할까?

매직 메서드는 Python 내부에서 특정한 상황에서 자동으로 호출되도록 설계되어 있기 때문입니다.

실행 코드 자동 호출되는 매직 메서드 설명

매직 메서드 실행 조건 내부 함수  설명 
object = ClassName() __init__() 객체가 생성될 때 자동 호출 (생성자)
print(object) __str__() 객체를 문자열로 변환할 때 호출
repr(object) __repr__() 객체의 공식적인 표현을 반환할 때 호출
object1 == object2 __eq__() 두 객체의 동등성을 비교할 때 호출
object1 < object2 __lt__() 두 객체를 비교할 때 호출 (미만)
len(object) __len__() 객체의 길이를 반환할 때 호출
object[0] __getitem__() 객체에서 특정 인덱스 값을 가져올 때 호출
object1 + object2 __add__() 두 객체를 더할 때 호출
object1 - object2 __sub__() 두 객체를 뺄 때 호출
object1 * object2 __mul__() 두 객체를 곱할 때 호출
object1 / object2 __truediv__() 두 객체를 나눌 때 호출
object() __call__() 객체를 함수처럼 호출할 때 실행
with object: __enter__(), __exit__() 컨텍스트 매니저(with문) 사용 시 실행

 

즉, 매직 메서드는 우리가 직접 호출하지 않더라도 Python 인터프리터가 특정한 연산이나 동작을 수행할 때 내부적으로 호출하는 방식으로 동작합니다.


(제일중요!!!) __init__() 메서드 (객체 초기화)

__init__() 메서드는 객체가 생성될 때 자동으로 호출되는 생성자 메서드입니다. 객체의 초기 상태를 설정하는 데 사용됩니다.

예제 코드 (models.py)

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    discount_price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.discount_price is None:
            self.discount_price = self.price * 0.9  # 기본 할인 가격 설정

사용 예시

product = Product(name="노트북", price=1500000)
print(product.discount_price)  # 1350000.0 (기본 할인 적용)

이처럼 __init__()은 객체가 생성될 때 초기 값을 설정하는 데 유용합니다.


매직 메서드가 여러 개 있는 경우, 어떻게 동작할까?

하나의 클래스에서 여러 개의 매직 메서드를 정의할 수 있습니다. 이 경우, 상황에 따라 적절한 매직 메서드가 호출됩니다.

예를 들어, __str__()과 __repr__()을 함께 정의한 경우:

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __str__(self):
        return f"{self.name} - {self.price}원"
    
    def __repr__(self):
        return f"Product(name={self.name}, price={self.price})"

동작 방식

product = Product(name="노트북", price=1500000)
print(product)  # __str__()이 호출됨
print(repr(product))  # __repr__()이 호출됨

또한, 비교 연산자 관련 매직 메서드가 여러 개 정의된 경우, Python은 필요에 따라 적절한 메서드를 호출합니다.

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __eq__(self, other):
        return self.price == other.price

    def __lt__(self, other):
        return self.price < other.price

동작 방식

product1 = Product(name="태블릿", price=800000)
product2 = Product(name="노트북", price=1500000)
print(product1 == product2)  # __eq__() 호출
print(product1 < product2)   # __lt__() 호출

각 매직 메서드는 해당하는 연산자가 사용될 때 자동으로 실행됩니다.


Python의 매직 메서드를 Django에 응용하면 아래와 같이 적용해 볼 수 있습니다. 

1. __str__() 메서드 (models.py)

__str__() 메서드는 객체를 문자열로 표현할 때 호출됩니다. Django의 Admin 페이지나 Shell에서 객체를 조회할 때 가독성을 높이는 데 유용합니다.

예제 코드 (models.py)

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __str__(self):
        return f"{self.name} - {self.price}원"

사용 예시 (views.py 또는 Shell)

product = Product(name="노트북", price=1500000)
print(product)  # 출력: 노트북 - 1500000원

2. __repr__() 메서드 (models.py)

__repr__() 메서드는 주로 개발자가 디버깅할 때 객체의 내부 정보를 확인하는 데 사용됩니다.

예제 코드 (models.py)

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __repr__(self):
        return f"Product(name={self.name}, price={self.price})"

사용 예시 (Shell)

product = Product(name="노트북", price=1500000)
print(repr(product))  # 출력: Product(name=노트북, price=1500000)

3. __eq__() 메서드 (models.py)

__eq__() 메서드는 두 객체가 같은지를 비교할 때 사용됩니다. 기본적으로 == 연산자를 사용할 때 호출됩니다.

예제 코드 (models.py)

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __eq__(self, other):
        if isinstance(other, Product):
            return self.name == other.name and self.price == other.price
        return False

사용 예시 (views.py 또는 Shell)

product1 = Product(name="노트북", price=1500000)
product2 = Product(name="노트북", price=1500000)
print(product1 == product2)  # 출력: True

4. __lt__() 및 비교 연산자 관련 매직 메서드 (models.py)

__lt__() 메서드는 < 연산자를 사용할 때 호출되며, 가격 비교와 같은 기능을 구현할 때 유용합니다.

예제 코드 (models.py)

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __lt__(self, other):
        if isinstance(other, Product):
            return self.price < other.price
        return NotImplemented

사용 예시 (views.py 또는 Shell)

product1 = Product(name="태블릿", price=800000)
product2 = Product(name="노트북", price=1500000)
print(product1 < product2)  # 출력: True

5. __hash__() 메서드 (models.py)

Django 모델 객체를 set 또는 dict의 키로 사용할 경우, __hash__() 메서드를 정의하여 객체의 고유성을 보장할 수 있습니다.

예제 코드 (models.py)

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __hash__(self):
        return hash((self.name, self.price))

사용 예시 (views.py 또는 Shell)

product_set = {Product(name="노트북", price=1500000), Product(name="태블릿", price=800000)}
print(product_set)

6. __call__() 메서드 (models.py)

객체를 함수처럼 호출할 수 있도록 하는 매직 메서드입니다.

예제 코드 (models.py)

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __call__(self, discount):
        return self.price * (1 - discount)

사용 예시 (views.py 또는 Shell)

product = Product(name="노트북", price=1500000)
print(product(0.1))  # 출력: 1350000.0 (10% 할인 적용)

7. __getitem__() 메서드 (models.py)

객체를 리스트나 딕셔너리처럼 인덱싱하여 값을 가져올 수 있도록 하는 메서드입니다.

예제 코드 (models.py)

class Product(models.Model):
    name = models.CharField(max_length=100)
    attributes = models.JSONField()

    def __getitem__(self, key):
        return self.attributes.get(key, None)

사용 예시 (views.py 또는 Shell)

product = Product(name="노트북", attributes={"color": "silver", "weight": "2kg"})
print(product["color"])  # 출력: silver

마무리

Django에서 매직 메서드를 적절히 활용하면 모델 객체를 보다 직관적으로 다룰 수 있습니다. __str__(), __repr__(), __eq__(), __lt__() 등 여러 메서드를 활용하여 객체를 비교하거나 연산할 수 있으며, __call__()과 __getitem__()을 사용하면 더 유연한 기능을 구현할 수 있습니다.

이제 여러분의 Django 프로젝트에서도 매직 메서드를 적극 활용해 보세요! 🚀

728x90
반응형