3

Google App Engine キュー API を使用しようとしていますが、これをテストする際に問題が発生しています。プロセスの一部で CSRF が機能していないようです。

私が理解しているように、APIはURLを呼び出してバックグラウンドでhttpリクエストを作成するタスクを実行します。

API が呼び出している完全な URL は → http://localhost.localdomain:8000/admin/cooking/recipe/36/chefworker/ です。

この例外が発生した場合:

Traceback (most recent call last):
  File "/home/mariocesar/Proyectos/Cooking/cooking/django/core/handlers/base.py", line 100, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/home/mariocesar/Proyectos/Cooking/cooking/django/views/decorators/csrf.py", line 24, in wrapped_view
    resp.csrf_exempt = True
AttributeError: 'NoneType' object has no attribute 'csrf_exempt'

そのため、csrf ミドルウェア、Cookie、一部のデータ、または応答自体が、GAE API がバックグラウンドでタスクを実行するために行う要求から欠落しています。

DjangoでCSRFを無効にせずにこれを解決するには? しかし、それはdjangoappengineで可能ですか?

私が使用しているmodels.pyとadmin.pyファイルは下にあります。

models.py

from django.db import models

class Recipe(models.Model):
    name = models.CharField(max_length=140)
    description = models.TextField()
    cooking_time = models.PositiveIntegerField()
    status = models.CharField(max_length=40)

    def __unicode__(self):
        return self.name

    def cookthis(self):
        import time
        self.status = 'The chef is cooking this recipe'
        self.save()
        time.sleep(obj.cooking_time)
        self.status = 'It\'s done ! the recipe is ready to serve'
        self.save()

admin.py

import logging

from django.contrib import admin, messages
from django.http import HttpResponse
from django.utils.functional import update_wrapper
from django.contrib.admin.util import unquote
from django.shortcuts import get_object_or_404, render_to_response
from django import template
from django.core.urlresolvers import reverse
from google.appengine.api import taskqueue
from google.appengine.api.taskqueue import TaskAlreadyExistsError

from cooking.models import Recipe
from django.views.decorators.csrf import csrf_exempt

class AdminRecipe(admin.ModelAdmin):
    def get_urls(self):
        from django.conf.urls.defaults import patterns, url

        def wrap(view):
            def wrapper(*args, **kwargs):
                return self.admin_site.admin_view(view)(*args, **kwargs)
            return update_wrapper(wrapper, view)

        info = self.model._meta.app_label, self.model._meta.module_name

        urlpatterns = super(AdminRecipe, self).get_urls()
        myurls = patterns('',
            url(r'^(.+)/cook/$',
                wrap(self.cook_view),
                name='%s_%s_chefworker' % info),
            url(r'^(.+)/chefworker/$',
                wrap(self.chefworker_worker),
                name='%s_%s_chefworker' % info),
        )
        return myurls + urlpatterns

    def cook_view(self, request, object_id, extra_context=None):
        obj = get_object_or_404(Recipe, pk=unquote(object_id))
        if request.POST:
            try:
                taskqueue.add(
                    name="recipie-%s" % obj.id,
                    url=reverse('admin:cooking_recipe_chefworker', args=(obj.id,))
                )
                messages.add_message(request, messages.INFO, 'Chef is cooking the recipe.')
            except TaskAlreadyExistsError:
                messages.add_message(request, messages.ERROR, 'chef is already cooking that recipe.')

        context_instance = template.RequestContext(request, current_app=self.admin_site.name)
        return render_to_response("admin/cooking/recipe/cook_view.html", {'object': obj}, context_instance=context_instance)

    #TODO: Add csrf token on form
    @csrf_exempt
    def chefworker_worker(self, request, object_id, extra_context=None):
        import time

        if request.POST:
            obj = get_object_or_404(Recipe, pk=unquote(object_id))
            obj.cookthis()

        return HttpResponse('done')

admin.site.register(Recipe, AdminRecipe)

重要な注意: このエラーをデバッグするのは困難でした。これは、dev_appserver ロガーが 403 エラーを発生させただけで、他の情報がないためです。そのため、ファイル google/appengine/api/taskqueue/taskqueue_stub.py の 574 行目にパッチを適用し、「logging.info('response --- \n%s' % result)」を追加して出力を取得する必要があります。

4

3 に答える 3

5

を有効にしている場合CsrfViewMiddleware、Django はcsrf_tokenビューへのすべての POST で を要求します。

@csrf_exemptDjango には、タスク キュー ビューに配置する必要があるデコレータ が用意されています。これにより、それらのビューに対してのみミドルウェアがオフになります。

CsrfViewMiddlewareまたは、完全に使用することを避け、代わり@csrf_protectに必要な場所でデコレーターを使用することもできます。これを行うことはお勧めしません。おそらく、あらゆる場所を保護し、タスク キュー ビューのいくつかの例外を切り開く方が安全です。

(最後の注意: 上記の両方の回答 -- あなたのビューに何か問題があるか、タスク キューに GET を使用する必要があるということです -- 私は間違っています。あなたのビューには何も問題はなく、POST は使用する正しい動詞です)タスク キュー タスクの場合)。

于 2011-03-18T00:16:31.577 に答える
3

csrf.pyのソースを見ると、ビュー関数が None を返す (または明示的に返さない場合、Python は暗黙的に None を返す) 場合にのみ発生するようです。あなたのコードを見ると、それがどのように発生するのかわかりませんが、これがあなたのデプロイされたコードであると確信していますか?

また、タスク キュー タスク内で使用したくないget_object_or_404場合もあります。オブジェクトが見つからない場合、404 がスローされ、タスクがエラーになり、無期限に再試行されます。

また、CSRF 保護も必要ありません (TODO による)。代わりに、タスク キューの URL が管理者専用としてマークされていることを確認し、タスク キュー サービスによってのみ呼び出されるようにします。

于 2011-01-27T03:53:47.563 に答える
1

私は専門家ではありませんが、POST の代わりに GET を使用してみてください。http://groups.google.com/group/django-non-relational/browse_thread/thread/e6baed5291aed957/d6c42150c8e246e1?lnk=gst&q=queue#d6c42150c8e246e1 (最後のエントリ)を参照してください。

于 2011-01-26T20:07:38.697 に答える