Как вставить объект JavaScript в Django JSONField

В моем веб-приложении django у меня есть две страницы. Одна — это форма, в которой пользователь может заполнить имя, размер, изображение и указать имена некоторых достопримечательностей на изображении. На следующей странице отображается это изображение и пользователь может разместить несколько кругов SVG, соответствующих точкам интереса, сверху, а когда пользователь отправляет, мне нужна форма с первой страницы и JSONField для расположения кругов (точки интереса). интерес) на изображении, чтобы все сохранить в одну модель.

В настоящее время мое решение представляет собой страницу с первой формой, а затем передать всю эту форму на следующую страницу. Поскольку я больше не хочу, чтобы пользователь видел эту форму, я поместил ее в скрытый div. Я визуализирую изображение из формы и с помощью JavaScript рисую круги, на которые нажимает пользователь. Когда кнопка отправки нажата, она запускает функцию в скрипте, которая отправляет форму во второй раз, но обновляет JSONField расположением всех кругов перед отправкой.

Приведенный ниже код работает до тех пор, пока форма не будет отправлена, но когда я добираюсь до функции view2, form.is_valid() всегда возвращает false. Подозреваю, что проблема здесь:

document.getElementById(id_spots).innerHTML = пятна

Я подумал, что, поскольку поле формы Django является JSONField, я мог бы назначить innerHTML в качестве объекта спотов, который я создал в JavaScript. Если я взгляну на то, как это влияет на HTML, [object Object] вставляется в текстовое поле Spots. Я также пробовал JSON.stringify(spots), но безрезультатно.

Кто-нибудь может определить проблему? И есть ли лучший способ присвоить значение JSONFiled для соответствия переменной в django?

просмотры.py

def view1(request):
    if request.method == 'POST':
        form = ImageForm(request.POST, request.FILES)
        if form.is_valid():
            b64Img = str(b64encode(form.files['img'].file.read()))[2:-1]
            return render(request, 'my-app/view2.html', { 'form': form, 'base': base, 'my_img': b64Img })
    else:
        form = ImageForm()
    return render(request, 'my-app/page1.html', { 'form':form, "base":base })

def view2(request):
    if request.method == 'POST':
        form = ImageForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
    else:
        form = DocumentsForm()
    return render(request, 'my-app/page1.html', {'form':form, 'base':base})

модели.py

class MyImage(models.Model):
    name = models.CharField(max_length=50)
    width = models.CharField(max_length=10)
    height = models.CharField(max_length=10)
    spot_names = models.CharField(max_length=1000)
    img = models.ImageField(default=None, upload_to='media/')
    spots = JSONField(blank=True)
    

    def __str__(self):
        return self.name

формы.py

class ImageForm(ModelForm):
    class Meta:
        model = MyImage
        fields = '__all__'

html/js

{% extends 'main/base.html' %}

{% block content %}

<div class="my-div">

    <div>
        <h1>Draw Dots!</h1>
        <h3 id="spot-selection">Click Spot: </h3>
    </div>
    <form id="drawForm" enctype="multipart/form-data" method="POST" action="/my-app/view2/">
        {% csrf_token %}
        <div style="display: none;">
            {{ form }}
        </div>
        
        <svg id="svg">
            <image id="my-img" href="data:image/png;base64,{{ my_img }}"/>          
        </svg>

        <button typr="button" id="submit-img" style="width: 100px;">Submit</button>
    </form>

</div>

{% endblock %}


{% block script_content %}

const spotNames = "{{ form.spot_names.value }}".split(",")
const width = {{ form.width.value }}
const height = {{ form.height.value }}
var spots = {}

this.window.addEventListener('DOMContentLoaded', (event) => {
    const svgElem = document.getElementsByTagName("svg")

    if (svgElem != undefined && svgElem.length != 0) {
        const svg = svgElem[0]
        const image = svg.firstChild
        var i = 0
        document.getElementById("spot-selection").innerHTML = "Click Spot: " + spotNames[i]
        
        svg.onclick = function(event) {
            if (i < spotNames.length) {
                var newCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle')
                let m = mousePositionSVG(event)
                newCircle.setAttribute('cx', m.x)
                newCircle.setAttribute('cy', m.y)
                newCircle.setAttribute('r', '10')
                newCircle.setAttribute('fill', 'red')
                svg.append(newCircle)
                spots[spotNames[i]] = [width*(m.x / document.getElementById("my-img").getBoundingClientRect().width), height*(m.y / document.getElementById("my-img").getBoundingClientRect().height)]
                i++
                if (spotNames[i] != undefined){
                    document.getElementById("spot-selection").innerHTML = "Click Spot: " + spotNames[i]
                }else{
                    document.getElementById("spot-selection").innerHTML = "All Spots Clicked!"
                }
                
            }
        }
        document.addEventListener("keydown", function(event){
            if (event.key == "Backspace" && i > 0){
                const circles = document.querySelectorAll("circle")
                circles[circles.length - 1].remove()
                i--
                document.getElementById("spot-selection").innerHTML = "Click Spot: " + spotNames[i]
            }
        })

    }
    document.getElementById("submit-img").onclick = function() {
        if (document.getElementById("spot-selection").innerHTML == "All Spots Clicked!"){
            document.getElementById("id_spots").innerHTML = spots
            console.log({{ form.spots.value }})
            document.getElementById("spotForm").submit()
        }
    }
})

function mousePositionSVG(e) {
    let svg = document.querySelector('svg')
    var p = svg.createSVGPoint()
    p.x = e.clientX
    p.y = e.clientY
    var ctm = svg.getScreenCTM().inverse();
    var p =  p.matrixTransform(ctm);
    return p;
}

{% endblock %}

person JasonFitz    schedule 30.04.2021    source источник


Ответы (1)


Использование JSON.stringify() на самом деле является правильным методом:

document.getElementById("id_spots").innerHTML = JSON.stringify(spots)

Я думал, что эта часть была ошибкой, потому что я получал ошибки при отправке формы, и единственная часть формы, которая меняется, — это JSONField. На самом деле ошибка, похоже, исходит от ImageField. Получается, что если передать форму в качестве контекста на другую страницу, поля ImageField не сохранятся.

Я сделал более актуальный пост о проблеме ImageField, поэтому любые новые ответы следует перенаправлять в этот пост: Как передать файл изображения с одной страницы на другую в многостраничной форме (Django)

person JasonFitz    schedule 01.05.2021