Django でカスタム モデル フィールドを実装しました。これは、ファイルを直接割り当てるだけでなく、URL 文字列を割り当てて画像を読み込むことができる画像フィールドです。
import uuid
import urllib.request
from django.core.files.base import ContentFile
from django.db import models
from django.db.models.fields.files import ImageFileDescriptor
class UrlImageFileDescriptor(ImageFileDescriptor):
def __set__(self, instance, value):
# If a string is used for assignment, it is used as URL
# to fetch an image from and store it on the server.
if isinstance(value, str):
try:
response = urllib.request.urlopen(value)
image = response.read()
name = str(uuid.uuid4()) + '.png'
value = ContentFile(image, name)
except:
print('Error fetching', value)
pass
super().__set__(instance, value)
class UrlImageField(models.ImageField):
descriptor_class = UrlImageFileDescriptor
一般的に、フィールドは機能します。しかし、何らかの理由で、Django 自体が内部的に文字列値を割り当てます。フィールドを使用するモデルのクエリ セットがフィルター処理されるたび__set__
に、文字列を使用して呼び出され、except 句の print ステートメントが発火しError fetching upload/to/50e170bf-61b6-4670-90d1-0369a8f9bdb4.png
ます。
django/db/models/query.py
Django 1.7c1 からの呼び出しを絞り込むことができました。
def get(self, *args, **kwargs):
"""
Performs the query and returns a single object matching the given
keyword arguments.
"""
clone = self.filter(*args, **kwargs)
if self.query.can_filter():
clone = clone.order_by()
clone = clone[:MAX_GET_RESULTS + 1]
num = len(clone) # This line causes setting of my field
if num == 1:
return clone._result_cache[0]
# ...
行が原因でフィールド__set__
が実行されるのはなぜですか? これを回避するには、入力値が有効な URL であることを検証できますが、まずその理由を知りたいです。