1

同じベースコードを使用できるはずの類似したビューがたくさんあるアプリケーションを作成しました。ただし、各メソッドには、メソッド内のさまざまな変曲点で特定の固有の特性があるため、コードを実際に再利用するためにこれを構造化する方法を理解できません。代わりに、カットアンドペーストの方法論を作成し、各メソッドを個別に微調整しました。アプリケーションのこの部分は、私がこれまでに作成した最初のPythonコードの一部であり、これを行うためのより良い方法があるはずですが、私はこの方法でそれを行うことに固執し、「動作する」ので、抜け道がわかりません。 。

基本ビューテンプレートは基本的に次のようになります。

def view_entity(request, entity_id=None):
    if request.method == 'POST':
        return _post_entity(request, entity_id)
    else:
        return _get_entity(request, entity_id)

def _get_entity(request, entity_id):
    data = _process_entity(request, entity_id)
    if 'redirect' in data:
        return data['redirect']
    else:
        return _render_entity(request, data['form'])

def _post_entity(request, entity_id):
    data = _process_entity(request, entity_id)
    if 'redirect' in data:
        return data['redirect']
    elif data['form'].is_valid():
        # custom post processing here
        instance = data['form'].save()
        return HttpResponseRedirect(reverse('entity', args=[instance.id]))
    else:
        return _render_entity(request, data['form'])


def _process_entity(request, entity_id):
    data = {}

    if entity_id != 'new':  # READ/UPDATE
        # sometimes there's custom code to retrieve the entity
        e = entity_id and get_object_or_404(Entity.objects, pk=entity_id)
        # sometimes there's custom code here that deauthorizes e
        # sometimes extra values are added to data here (e.g. parent entity)
        if e:
            if request.method == 'POST':
                data['form'] = EntityForm(request.POST, instance=e)
                # sometimes there's a conditional here for CustomEntityForm
            else:
                data['form'] = EntityForm(instance=e)
        else:  # user not authorized for this entity
            return {'redirect': HttpResponseRedirect(reverse('home'))}
        # sometimes there's custom code here for certain entity types

    else:  # CREATE
        if request.method == 'POST':
            data['form'] = EntityForm(request.POST)
        else:
            data['form'] = EntityForm()

    # sometimes extra key/values are added to data here
    return data

考えられるすべてのバリエーションを含めたわけではありませんが、ご覧のとおり、この_process_entity方法では、処理されるエンティティのタイプに基づいて、多くの個別のカスタマイズが必要です。これが、これを処理するためのDRYの方法を理解できない主な理由です。

どんな助けでもありがたいです、ありがとう!

4

2 に答える 2

1

クラスベースのビューを使用します。クラスからの継承やその他の機能を使用して、ビューをより再利用可能にすることができます。組み込みの汎用ビューを使用して、基本的なタスクの一部を簡素化することもできます。

クラスベースのビューのドキュメントを確認してください。これも読むことができます

于 2012-07-12T20:06:05.933 に答える
0

そのため、すべてのビューが継承する基本クラスにコードをリファクタリングすることになりました。(まだ)複数のビューにリファクタリングすることはしませんでしたが、代わりに、処理メソッド内にフックを挿入することで、カスタム処理メソッドを持つ問題を解決しました。

以下から継承する基本クラスの要点は次のDetailViewとおりです。

class MyDetailView(DetailView):
    context = {}

    def get(self, request, *args, **kwargs):
        self._process(request, *args, **kwargs)

        if 'redirect' in self.context:
            return HttpResponseRedirect(self.context['redirect'])

        else:
            return self._render(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self._process(request, *args, **kwargs)

        if 'redirect' in self.context:
            return HttpResponseRedirect(self.context['redirect'])

        elif self.context['form'].is_valid():
            self._get_hook('_pre_save')(request, *args, **kwargs)
            return self._save(request, *args, **kwargs)

        else:
            return self._render(request, *args, **kwargs)

    def _process(self, request, *args, **kwargs):
        form = getattr(app.forms, '%sForm' % self.model.__name__)

        if kwargs['pk'] != 'new':  # READ/UPDATE
            self.object = self.get_object(request, *args, **kwargs)

            self._get_hook('_auth')(request, *args, **kwargs)

            if not self.object:  # user not authorized for this entity
                return {'redirect': reverse(
                    '%s_list' % self.model.__name__.lower())}

        self.context['form'] = form(
            data=request.POST if request.method == 'POST' else None,
            instance=self.object if hasattr(self, 'object') else None)

        self._get_hook('_post_process')(request, *args, **kwargs)

    def _get_hook(self, hook_name):
        try:
            return getattr(self, '%s_hook' % hook_name)
        except AttributeError, e:
            def noop(*args, **kwargs):
                pass
            return noop

注意すべき重要な部分は、_get_hookメソッドと、それを使用する他のメソッド内の場所です。そうすれば、いくつかの複雑なビューで、次のようなカスタムコードを挿入できます。

class ComplexDetailView(MyDetailView):
    def _post_process_hook(self, request, *args, **kwargs):
        # here I can add stuff to self.context using 
        # self.model, self.object, request.POST or whatever

これにより、カスタムビューは機能の大部分を継承するため、小さくなりますが、その特定のビューに必要な微調整を追加できます。

于 2012-07-18T15:32:35.540 に答える