Django2:提交blob并将其存储为图像文件

时间:2018-05-15 07:54:45

标签: django django-models django-views blob

在阅读完本教程后,我做了一些Django项目,但我不是Django的专家。

我正在尝试截取当前页面并将其存储(如果不存在)。

要实现这一目标,我们需要做一些事情:

  1. 获取当前页面截屏的功能
  2. 将此图像异步发布到应存储它的视图的功能
  3. 存储已发布图片的视图
  4. 然而,屏幕截图功能导致Blob,我无法获得Django视图来正确处理它。

    此处提供了一个演示项目:https://gitlab.com/SumNeuron/so_save_blob

    截屏功能

    const screenshot = (function() {
      function urlsToAbsolute(nodeList) {
          if (!nodeList.length) {
              return [];
          }
          var attrName = 'href';
          if (nodeList[0].__proto__ === HTMLImageElement.prototype
          || nodeList[0].__proto__ === HTMLScriptElement.prototype) {
              attrName = 'src';
          }
          nodeList = [].map.call(nodeList, function (el, i) {
              var attr = el.getAttribute(attrName);
              if (!attr) {
                  return;
              }
              var absURL = /^(https?|data):/i.test(attr);
              if (absURL) {
                  return el;
              } else {
                  return el;
              }
          });
          return nodeList;
      }
      function addOnPageLoad_() {
          window.addEventListener('DOMContentLoaded', function (e) {
              var scrollX = document.documentElement.dataset.scrollX || 0;
              var scrollY = document.documentElement.dataset.scrollY || 0;
              window.scrollTo(scrollX, scrollY);
          });
      }
      function capturePage(){
        urlsToAbsolute(document.images);
        urlsToAbsolute(document.querySelectorAll("link[rel='stylesheet']"));
        var screenshot = document.documentElement.cloneNode(true);
        var b = document.createElement('base');
        b.href = document.location.protocol + '//' + location.host;
        var head = screenshot.querySelector('head');
        head.insertBefore(b, head.firstChild);
        screenshot.style.pointerEvents = 'none';
        screenshot.style.overflow = 'hidden';
        screenshot.style.webkitUserSelect = 'none';
        screenshot.style.mozUserSelect = 'none';
        screenshot.style.msUserSelect = 'none';
        screenshot.style.oUserSelect = 'none';
        screenshot.style.userSelect = 'none';
        screenshot.dataset.scrollX = window.scrollX;
        screenshot.dataset.scrollY = window.scrollY;
        var script = document.createElement('script');
        script.textContent = '(' + addOnPageLoad_.toString() + ')();';
        screenshot.querySelector('body').appendChild(script);
        var blob = new Blob([screenshot.outerHTML], {
            type: 'text/html'
        });
        return blob;
      }
    
      return capturePage
    })()
    

    异步发布Blob的功能

    function setupAjaxWithCSRFToken() {
      // using jQuery
      var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
      function csrfSafeMethod(method) {
          // these HTTP methods do not require CSRF protection
          return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
      }
      // set csrf header
      $.ajaxSetup({
          beforeSend: function(xhr, settings) {
              if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                  xhr.setRequestHeader("X-CSRFToken", csrftoken);
              }
          }
      });
    
    }
    
    function asyncSubmitBlob( url, blob ) {
      var fd = new FormData();
      fd.append('image', blob);
      $.ajax({
          url: url,
          type: "POST",
          data: fd,
          contentType: false,
          processData: false,
          success: function(response){ console.log(response) },
          error: function(data){ console.log(data) }
      })
    }
    

    所以提交当前页面的截图:

    setupAjaxWithCSRFToken()
    const page = window.location.pathname;
    const blob_url = "{% url 'my-app:post_blob' 'REPLACE' %}".replace(/REPLACE/,page == '/' ? '' : page)
    asyncSubmitBlob( blob_url, screenshot() )
    

    查看以存储已发布的blob图像

    urls.py

    ...
    from django.urls import include, path
    ...
    app_name='my-app'
    url_patterns=[
      ...
      path('post_blob/', views.post_blob, {'page':'/'},name='post_blob'),
      path('post_blob/<page>', views.post_blob,name='post_blob'),
      ...
    ]
    

    views.py

    from .models import PageBlob
    ...
    def post_blob(request, page):
        if request.FILES: # save screenshot of specified page
            try:
    
                pb = PageBlob.objects.all().filter(page=page))
                if not pb.count():
                    pb = PageBlob()
                    pb.page = page
                    pb.blob = request.FILES['image']
                    pb.save()
    
    
                    return HttpResponse('Blob Submitted')
            except:
                return HttpResponse('[App::my-app]\tError when requesting page_image({page})'.format(page=page))
        else: # return screenshot of requested page
            try:
                # get objects storing screenshot for requested page
                pb = PageBlob.objects.all().filter(page=page)
                # if one exists
                if pb.count():
                    pb = pb[0]
    
                    ## this just returns the string literal "blob"
                    return HttpResponse(str(pb.blob))
    
    
                return HttpResponse('[App::my-app]\tNo blob for {page}'.format(page=page))
            except:
                return HttpResponse('[App::my-app]\tError when trying to retrieve blob for {page}'.format(page=page))
        return HttpResponse('Another response')
    

    models.py

    class PageBlob(models.Model):
        page = models.CharField(max_length=500)
        blob = models.TextField(db_column='data', blank=True)
    

    但我似乎无法忠实地捕获和检索斑点。

    许多S.O.存储blob的问题使用模型方法import base64来编码和解码blob。有人甚至建议使用BinaryField。但是,Django的文档坚定地指出BinaryField不能替代静态文件的处理。

    那么我怎么能实现这个目标呢?

    所以。帖子我发现有助于实现这一目标

0 个答案:

没有答案