Django2: отправляйте и храните капли как файлы изображений - PullRequest
0 голосов
/ 15 мая 2018

Я сделал несколько проектов Django после прочтения руководства, но я ни в коем случае не эксперт в Django.

Я пытаюсь сделать скриншот текущей страницы и сохранить его (если он не существует).

Для этого нам понадобятся несколько вещей:

  1. функция для получения снимка экрана текущей страницы
  2. функция для асинхронной отправки этого изображения в представление, в котором оно должно храниться
  3. просмотр, в котором хранится размещенное изображение

Однако функция снимка экрана приводит к появлению 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() )

Просмотр сохраненного изображения блоба

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)

Но, похоже, я не могу точно захватить и получить блоб.

Многие С.О. вопросы хранения больших двоичных объектов используют модельный подход с import base64 для кодирования и декодирования большого двоичного объекта. Один даже рекомендует использовать BinaryField. Однако в документации Django твердо сказано, что BinaryField не является заменой для обработки статических файлов.

Так, как я мог достигнуть этого?

ТАК. сообщения, которые я нашел полезными, чтобы получить это далеко
...