django:如何将传入的POST数据用作流式处理的文件类对象

django:如何将传入的POST数据用作流式处理的文件类对象

问题描述:

我正在使用python + Django处理传入的Web请求,该请求可以发布大量附加为POST数据字段之一的JSON(例如var1 = abc & json_var = lots_of_data & other_var = xxx)。我想用自己的流式json解析器以流式处理JSON,它采用类似文件的句柄作为其输入参数。它从https://docs.djangoproject.com/en/1.11/ref/request-response/出现,这是可行的,使用HttpRequest.__iter__(),但我找不到任何如何用我自己的代码(即不是像xml.etree.ElementTree导入库)实现这个例子。django:如何将传入的POST数据用作流式处理的文件类对象

基本上,我想执行以下操作:

POST请求瓦特/大JSON =>的Django /蟒=>创建类文件句柄读POST =>流网址解码器=>流JSON处理器

我可以使用ijson作为流式JSON处理器。我如何填写这两个差距来创建类似于文件的POST数据句柄并将它传递给流url解码器?宁愿不要推出我自己的,但我想如果有必要我可以。

__iter__()只是一个xreadlines的包装,它反过来只是一个循环,它使用HttpRequest的输入流一次调用并产生一行数据。所以,你可以用某个这样

parser = MyJsonParser() 
for line in (request): 
    parser.process(line) 

您还没有发布的代码,所以你将有你认为合适的适应替代人工在该示例代码。

另请注意,根据您的设置,这可能是也可能不是真正的流式传输过程。很有可能您的服务器机制会一次读取整个帖子主体,并将其传递到您的视图,而不一次发送一行。在这种情况下,流媒体的外观是虚幻的。

+0

谢谢。假设传入的请求是以分块方式编码的,是否有任何方法可以确保服务器以块的形式接收数据 - 或者至少会限制它分配的内存以获取发布数据?即如果传入的POST大小为2GB,我不希望服务器将它全部放在内存中。理想情况下,我可以在数据进入时处理数据,或者在处理数据之前使用固定内存将数据写入磁盘。 – mwag

+0

我认为这个评论应该是一个新问题。即使这个问题太广泛了。您必须将其限制到特定的服务器 – e4c5

+0

另外,如果POST数据是经过网址编码的,那么对迭代器的第一次调用将返回单行中的所有数据,即使它是例如。 2GB(或可能不是如果发送chunked?)重新“限制它到一个特定的服务器”:我认为这个问题隐式地指定了一个服务器(Django的默认web服务器) - 你可以解释什么add'l信息将需要? – mwag

我只能通过滚动我自己的生成器和迭代器来解决这个问题。有几个关键要解决这个问题:

  • 找到如何访问类似于文件的处理POST数据的情况下数据发送chunked。我能找到这个在request.META.get('wsgi.input'),我定位是通过使用this post转储所有的请求的属性
  • 推出自己的发电机来读取一个类文件句柄和产量(varname的,data_chunk)对
  • 推出自己的发电机的基础上,this post,修改后的版本,以创建具有正常的读()操作,但有3个附加特性类似文件句柄:
    • f.varname返回正在被读取当前的变量名
    • 数据在从read()返回之前是url-unencoded()
    • f.next_pair()提前处理读取下一个变量。所以,调用f.read()直到它完成第一个变量,然后如果有另一个变量,f.next_pair()将返回true和f。阅读()可以再次调用,直到下一个变量进行读取
  • 进一步流处理可以在主回路

实现全部放在一起,它看起来是这样的:

f = request.META.get('wsgi.input') 
ff = some_magic_adaptor(qs_from_file_to_generator(f)) 

while ff.next_pair(): 
    print 'varname:' + ff.varname 
    if ff.varname == 'stream_parse_this': 
     parser = stream_parser(ff) 
     for event_results in parser: 
      do_something 

    while True: 
     data = ff.read(buffer_size) 
     if not data: 
      break 
     do_something_with_data_chunk(data)