이번에는 Django models에서 decorator 중 하나인 @property를 알아보도록 하겠다.
다음의 예시를 보자:
# models.py
...
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.FloatField()
digital = models.BooleanField(default=False, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
...
Django에서 우리가 특정 모델에 사진을 부여하고 싶을 때 이런 식으로 사용할 수 있을 것이다. 또한, 이를 불러오기 위해서는 views.py 와 html template을 다음과 비슷하게 설정을 해야할 것이다:
# views.py
...
def store(request):
products = Product.objects.all()
context = {'products':products}
return render(request, 'store/store.html', context)
<!-- store.html -->
...
<img class="thumbnail" src={{product.image.url}}>
...
이를 통해 다음과 같은 사진을 웹사이트에 표현할 수 있을 것이다:
모든 것이 잘 되는 듯 하다. 하지만 만약 우리가 해당 제품에 대한 사진을 업로드 하는 것을 깜빡했다면 어떻게 되는 것일까??
다음과 같은 에러가 발생한다. 따라서 우리는 애초에 사진을 설정해주지 않으면 에러가 발생한다는 것을 알 수 있다. 하지만 만약 우리가 이 에러가 발생하는 것을 막고, 만약 사진이 없다면 기본적으로 특정 사진을 정해주게끔 하고 싶다면어떻게 해야될까?
※ @property decorator
위에서 원하는 방식을 하려면, @property를 사용하는 방법이 있다 (단순히 함수로 만들수도 있다):
# models.py
...
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.FloatField()
digital = models.BooleanField(default=False, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
@property
def imageURL(self):
try:
url = self.image.url
except:
url = 'images/placeholder.png'
return url
...
@property decorator는, 메소드를 마치 필드인 것처럼 취급할 수 있게끔 해준다. 즉, html template에서 다음과 같이 불러올 수 있다는 것이다:
<!-- store.html -->
...
<img class="thumbnail" src={{product.imageURL}}>
...
이런식으로 불러오게 된다면, Product class에 있는 imageURL에서 self.image.url을 찾아보도록 시도를 하고 만약 없다면 바로 images 폴더에 있는 placeholder.png를 불러온다는 것을 알 수 있다.
사실 저 @property가 없이 함수만 있어도 html template 에서는 {{ product.imageURL }} 로 불러올 수 있다. 하지만 이렇게 해주는 이유는 @property를 넣음으로써, 함수가 아닌 필드로 불러오기 때문에, views.py에서는 product.imageURL()이 아닌 product.imageURL 과 같은 형식으로 불러올 수 있는 것이다.
메소드를 마치 필드인 것처럼 취급할 수 있게끔 하는 것은, 이 외에도 getter 과 setter 를 사용할때 필요하기도 한데, 이에 대해서는 다음에 getter/setter를 다루어볼 때 함께 다루어볼 수 있도록 하겠다.