0

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.pyDjango 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 であることを検証できますが、まずその理由を知りたいです。

4

1 に答える 1

4

ストーリーはトレースバックにあります。クエリの長​​さを取得するには:

File "C:\repository\virtualenv\lib\site-packages\django\db\models\query.py" in get
  350.         num = len(clone)

すべてのクエリ結果をリストにフェッチします。

File "C:\repository\virtualenv\lib\site-packages\django\db\models\query.py" in __len__
  122.         self._fetch_all()
File "C:\repository\virtualenv\lib\site-packages\django\db\models\query.py" in _fetch_all
  966.             self._result_cache = list(self.iterator())

クエリ結果ごとに、db のデータを使用してモデル オブジェクトを作成します。

File "C:\repository\virtualenv\lib\site-packages\django\db\models\query.py" in iterator
  275.                     obj = model(*row_data)

モデル オブジェクトを作成するには、モデルの各フィールドを設定します。

File "C:\repository\virtualenv\lib\site-packages\django\db\models\base.py" in __init__
  383.                 setattr(self, field.attname, val)

__set__カスタムモデルフィールドで呼び出すことになります:

File "C:\repository\invoicepad\apps\customer\fields.py" in __set__
  18.                           response = urllib.request.urlopen(value)

この背後にある大規模な理由についてこれ以上言うのは難しいです.Djangoについてあまり知らないことと、あなたのデータベース構造がどのようなものか知らないためです. UriImageFieldただし、基本的には、記述子を実装した方法に対して実際には有効ではないデータが含まれているデータベースフィールドにデータが入力されているように見えます。(たとえば、エラーから判断すると、データベースには'upload/to/50e170bf-61b6-4670-90d1-0369a8f9bdb4.png'ありますが、実際にはそのようなファイルはありません。)

于 2014-07-27T01:16:12.150 に答える