2011-01-26 7 views
3

Google App Engine 대기열 API를 사용하려고하는데이 문제를 테스트하는 데 문제가 있습니다. 프로세스의 일부에서 CSRF가 작동하지 않는 것으로 보입니다.Django에서 Google App Engine 대기열 서비스 사용

api가 url을 호출하고 백그라운드에서 http 요청을 작성하는 작업을 수행함을 이해합니다.

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 미들웨어, 쿠키, 데이터 나 응답이 자체에서 누락 :이 예외가 발생하면 전체 URL이 API가 호출되는

http://localhost.localdomain:8000/admin/cooking/recipe/36/chefworker/

→이다 GAE API가 백그라운드에서 작업을 실행하도록 요청합니다.

장고에서 CSRF를 비활성화하지 않고이를 해결하는 방법은 무엇입니까? 그러나, 그것은 장고 펭귄과 함께 할 수 있습니다.

아래는 내가 사용중인 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 ('응답 --- \ n % s'% 결과)"를 추가하여 출력을 얻어야합니다.

답변

1

저는 전문가는 아니지만 POST 대신 GET을 사용해 볼 수 있습니다. http://groups.google.com/group/django-non-relational/browse_thread/thread/e6baed5291aed957/d6c42150c8e246e1?lnk=gst&q=queue#d6c42150c8e246e1 (마지막 항목)

+0

GET을 메서드로 사용하면 프로세스가 백그라운드에서 실행되고 있지 않은 것 같습니다. –

+0

GET을 사용하는 것은 실제로는 가장 깨끗한 작업이 아닙니다. 거의 항상 작업 대기열에 POST를 사용하는 것이 좋습니다. 아래 나의 새로운 대답을 참조하십시오. –

3

source의 csrf.py를 보면,보기 기능이 없음을 반환하거나 명시 적으로 반환하지 않으면 파이썬이 없음을 암시 적으로 반환하는 경우에만 발생하는 것처럼 보입니다. 귀하의 코드를 살펴보면 어떻게 될지 모르겠지만, 이것이 정확한 코드입니까?

또한 작업 대기열 작업 내에서 get_object_or_404을 사용하지 않으려는 경우 - 개체를 찾을 수 없으면 404 오류가 발생하여 작업 오류가 발생하고 무제한 시도가 다시 발생합니다.

또한 TODO별로 CSRF 보호가 필요하지 않습니다. 대신, 작업 대기열 URL이 관리자 전용으로 표시되고 작업 대기열 서비스에 의해서만 호출되어야합니다.

+0

예, 실제로 http 응답이 문제입니다. GAE API는 작업을 시작하기 위해 웹 요청을 사용하며 이것은 장고 미들웨어 (CSRF 미들웨어)와 완전히 통합되지 않습니다. 가장 좋은 해결책은 POST 메서드를 사용하지 않고 @Guy가 권장하는 작업에 GET 메서드를 사용하는 것입니다. –

+0

@Mario 정말 '최상의'솔루션처럼 보이지 않습니다. 가장 좋은 해결책은보기 기능에서 없음을 반환하는 방법을 파악하는 것입니다. –

+0

@Nick, CSRF 미들웨어와 관련된 @csrf_exempt 데코레이터는 Google API가 작업을 호출 할 때 설정되지 않은 변수를 찾습니다. 이것은 403 또는 301 http erros를 얻는 것을 reasing이었다. –

4

CsrfViewMiddleware을 사용하는 경우 Django는보기에 대한 모든 POST에 csrf_token을 요구합니다.

Django는 작업 큐 뷰에 배치해야하는 장식자인 @csrf_exempt을 제공합니다. 이렇게하면 해당 뷰에 대한 미들웨어가 해제됩니다.

또는 CsrfViewMiddleware을 사용하지 않고 대신 필요한 곳에서 @csrf_protect 데코레이터를 사용할 수 있습니다. 이렇게하는 것을 권장하지 않습니다. 모든 곳을 보호하고 작업 큐 뷰에 대해 소수의 예외를 제거하는 것이 더 안전합니다.

(위의 두 가지 답변 : 위의 두 가지 답변 -보기가 잘못되었거나 작업 대기열에 GET을 사용해야 함 - 잘못 생각해주세요.보기에는 아무 문제가 없습니다. POST는 올바른 동사가 작업 대기열 작업에 사용합니다.)

+0

옙 ..이게 내 문제를 해결했습니다 :) –