在Django中对一个类进行子类化以接受另一个kwarg

时间:2012-08-20 20:59:39

标签: python ajax django model subclass

我正在尝试将ajax上传器子类化以接受django模型的hash_id(以便它可以在成功上载图像时创建模型)并且无法传递额外的kwarg(widget2_hash_id)。我很感激如何正确添加kwarg的指导。

views.py:

class S3UploadBackend_Widget2EditableImage(S3UploadBackend):

  def upload(self, *args, **kwargs):
    self.widget2_hash_id = kwargs.pop('widget2_hash_id')

    k = Key(self._bucket)
    chunk = uploaded.read()
    k.set_contents_from_string(chunk)

    # create uploaded file
    fh = tempfile.TemporaryFile()
    k.get_contents_to_file(fh)
    fh.seek(0)
    saveable_file = SimpleUploadedFile(k.name, fh.read())

    # delete aws key and close tempfile
    _media_bucket.delete_key(k)
    fh.close()

    self.widget2 = Widget2.objects.get(hash_id = self.widget2_hash_id)

    self.widget2_editable_image = Widget2EditableImage(image = saveable_file, widget2 = self.widget2)
    self.widget2_editable_image.save()

    if k.key:
      self.key = k.key
      return True
    else:
      # Key creation failed.
      return False

  def upload_complete(self, request, filename):
    # Manually add S3 key to ajaxuploader JSONresponse
    res =  {"aws_file_key": self.key, "url": self.widget2_editable_image.image.url}

views.py:

widget2_editable_image_ajax_uploader = AjaxFileUploader(backend=S3UploadBackend_Widget2EditableImage)

urls.py:

(r'^widget2/widget2_image_upload/(?P<widget2_hash_id>[a-fA-F0-9]+)/$', 'widget2.views.widget2_editable_image_ajax_uploader'),

回溯:

Traceback (most recent call last):
  File "/home/zain/XXX/lib/Django-1.3.1/django/core/handlers/base.py", line 111, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
TypeError: __call__() got an unexpected keyword argument 'widget2_hash_id'

[20/Aug/2012 20:50:44] "POST /widget2/widget2_image_upload/d9dc4fab3d5e0eb45995/?qqfile=s3Zas.jpg HTTP/1.1" 500 870358

编辑:我在课堂上尝试了这个并得到同样的错误:

def __init__(self, *args, **kwargs):
  try:
    self.widget2 = Widget2.objects.get(hash_id = kwargs.pop('widget2_hash_id'))
  except KeyError:
    self.widget2_hash_id = None
  super(S3UploadBackend_Widget2EditableImage, self).__init__(*args, **kwargs)

EDIT2:这是AjaxFileUploader类:

class AjaxFileUploader(object):                                                                                                                                                                                                                                                                                                                  
    def __init__(self, backend=None, **kwargs):                           
        if backend is None:                                               
            backend = LocalUploadBackend                                  
        self.get_backend = lambda: backend(**kwargs)                      

    def __call__(self, request, **kwargs):                                
        return self._ajax_upload(request)                                 

    def _ajax_upload(self, request):                                      
        if request.method == "POST":                                      
            if request.is_ajax():                                         
                # the file is stored raw in the request                   
                upload = request                                          
                is_raw = True                                             
                # AJAX Upload will pass the filename in the querystring if it
                # is the "advanced" ajax upload                           
                try:                                                      
                    filename = request.GET['qqfile']                      

                except KeyError:                                          
                    return HttpResponseBadRequest("AJAX request not valid")
            # not an ajax upload, so it was the "basic" iframe version with
            # submission via form                                         
            else:                                                         
                is_raw = False                                            
                if len(request.FILES) == 1:                               
                    # FILES is a dictionary in Django but Ajax Upload gives
                    # the uploaded file an ID based on a random number, so it
                    # cannot be guessed here in the code. Rather than editing
                    # Ajax Upload to pass the ID in the querystring, observe
                    # that each upload is a separate request, so FILES should
                    # only have one entry. Thus, we can just grab the first
                    # (and only) value in the dict.                       
                    upload = request.FILES.values()[0]                    
                else:                                                     
                    raise Http404("Bad Upload")                           
                filename = upload.name                                    

            backend = self.get_backend()                                  

            # custom filename handler                                     
            # Override filename to avoid collisons                        
            filename = unicode(hashlib.sha1(str(datetime.datetime.now())).hexdigest()[0:6]) + filename
            filename = (backend.update_filename(request, filename)        
                        or filename)                                      

            # save the file                                               
            backend.setup(filename)                                       
            success = backend.upload(upload, filename, is_raw)            

            # callback                                                    
            extra_context = backend.upload_complete(request, filename)    

            # let Ajax Upload know whether we saved it or not             
            ret_json = {'success': success, 'filename': filename}         
            if extra_context is not None:                                 
                ret_json.update(extra_context)                            

              return HttpResponse(json.dumps(ret_json, cls=DjangoJSONEncoder))

1 个答案:

答案 0 :(得分:3)

解释

urls.py中,你有这个:

(r'^widget2/widget2_image_upload/(?P<widget2_hash_id>[a-fA-F0-9]+)/$', 'widget2.views.widget2_editable_image_ajax_uploader'),

url匹配时,django会将请求以及args分派给给定视图,因此,如果我们将其分解,则以下参数将传递给{{ 1}}(widget2.views.widget2_editable_image_ajax_uploader):

view

现在,request *args: [] *kwargs: {'widget2_hash_id':'somehashid',} dispatch词汇中意味着什么?嗯,基本上,它意味着呼叫功能。

恰好django有一个调用方法,因此widget2.views.widget2_editable_image_ajax_uploader会很乐意使用上面提到的参数调用此方法。

不幸的是,由于你的视图不接受django kwarg,python会引发错误。它是做什么的。

我认为你丢失的重点在于你错过了这样一个事实:它是通过额外的arg而不是后端的视图。然后,视图的工作就是将其传递给后端。

解决方案

简单的

您只需要修改widget2_hash_id方法,使其接受额外的arg,然后将其传递给__call__方法。

然后,您需要将参数传递给后端。为此,您应该更改以下行:

_ajax_upload

backend.upload(upload, filename, is_raw)

正确的

现在,我必须说我对你在做什么感到有点困惑。您似乎将对象用作视图,但是,为什么不使用backend.upload(upload, filename, is_raw, widget2_hash_id) 的真棒class-based views

以前的文档非常缺乏(老实说我不知道​​是否仍然如此),所以这里是a small guide to get you started

花一些时间学习和使用它们。它们非常易于使用和扩展,从长远来看,它们将为您节省大量时间。

在结束语

请使用django forms,因为他们摇滚。