0

Django DirtyFields を実装している場合、テストでフィクスチャを使用する際に既知の問題はありますか?

フィクスチャとカバレッジでを使用しdjango_noseます。いくつかのカスタムアクティビティを実行するNoseTestSuiteRunnerために実装しようとしていました。私が行った唯一の変更は次のとおりです。django-dirtyfieldspost_save()

from dirtyfields import DirtyFieldsMixin


class BaseModel(DirtyFieldsMixin, models.Model):
    """
    Base model
    """
    class Meta:
        abstract = True

これを使用しBaseModelて、他のほとんどのモデルを拡張します。原因を追加するDirtyFieldsMixinと、次のエラーが繰り返されてテストが終了します。

Problem installing fixture '/home/ricomoss/workspace/project/settings/../apps/contracts/fixtures/test_contracts_data.json': Traceback (most recent call last):
  File "/home/ricomoss/.virtualenvs/project/local/lib/python2.7/site-packages/django/core/management/commands/loaddata.py", line 193, in handle
    for obj in objects:
  File "/home/ricomoss/.virtualenvs/project/local/lib/python2.7/site-packages/django/core/serializers/json.py", line 47, in Deserializer
    raise DeserializationError(e)
DeserializationError: Field matching query does not exist.

私が知る限り、このエラーはフィクスチャがロードしようとするたびに発生します。何かご意見は? DirtyFieldsMixinフィクスチャを更新する必要がある新しいフィールド (必須フィールドはもちろん) が含まれていません。

編集 1: 私の問題は、Djangoのフィクスチャ/信号の問題に直接関係しているようです。定義を見るとDirtyFieldsMixin、問題がどこにあるかすぐにわかります (私はこれを確認しました)。

class DirtyFieldsMixin(object):
    def __init__(self, *args, **kwargs):
        super(DirtyFieldsMixin, self).__init__(*args, **kwargs)
        post_save.connect(
            self._reset_state, sender=self.__class__,
            dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format(
                self.__class__.__name__))
        self._reset_state()

    def _reset_state(self, *args, **kwargs):
        self._original_state = self._as_dict()

    def _as_dict(self):
        return dict([(f.name, getattr(self, f.name)) for f in
                     self._meta.local_fields if not f.rel])

    def get_dirty_fields(self):
        new_state = self._as_dict()
        return dict([(key, value) for key, value in
                     self._original_state.iteritems()
                     if value != new_state[key]])

    def is_dirty(self):
        # in order to be dirty we need to have been saved at least once, so we
        # check for a primary key and we need our dirty fields to not be empty
        if not self.pk:
            return True
        return {} != self.get_dirty_fields()

具体的には、

post_save.connect(self._reset_state, sender=self.__class__,
                  dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format(
                  self.__class__.__name__))

与えられた解決策に従ってデコレータを作成しようとしました。デコレータの実装が間違っているか、この状況では機能しません。この状況での使用について少し混乱しています。

にデコレータを配置しますか__init__:

@utils.disable_for_loaddata
def __init__(self, *args, **kwargs):
    super(DirtyFieldsMixin, self).__init__(*args, **kwargs)
    post_save.connect(
        self._reset_state, sender=self.__class__,
        dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format(
            self.__class__.__name__))
    self._reset_state()

この場合、まだ失敗します。助言がありますか?

EDIT 2:メソッドにデコレータを追加しようとしました_reset_state。これもうまくいきません。

@utils.disable_for_loaddata
def _reset_state(self, *args, **kwargs):
    self._original_state = self._as_dict()

編集 3: 私は進歩していると思います。inspect.stack()デコレーターの部分を__init__直接 (post_save呼び出しのすぐ上)に移動しました。

私のテスト スイートはまだ正しく実行されていませんが、他のアクティビティが発生しています。loaddata エラーが発生しなくなりました。

def __init__(self, *args, **kwargs):
    super(DirtyFieldsMixin, self).__init__(*args, **kwargs)

    import inspect
    for fr in inspect.stack():
        if inspect.getmodulename(fr[1]) == 'loaddata':
            return
    post_save.connect(
        self._reset_state, sender=self.__class__,
        dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format(
            self.__class__.__name__))
    self._reset_state()

編集 4: このプロセスのために独自の mixin を作成することにしました。自分の目的のために信号を使用する必要があるとは思いません。その結果、メソッドをオーバーライドし、save()これを特別な方法で処理します。

4

2 に答える 2