微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将 JavaScript 对象插入 Django JSONField

如何解决如何将 JavaScript 对象插入 Django JSONField

在我的 django web 应用程序中,我有两页 - 一个是供用户填写名称、大小、图像并指定图像上某些兴趣点的名称的表单。下一页显示该图像并允许用户在顶部放置一些与兴趣点相对应的 SVG 圆圈,当用户提交时,我想要第一页的表单和一个 JSONField 用于圆圈的位置(点兴趣)以将所有图像保存到一个模型中。

目前,我的解决方案是使用第一个表单的页面,然后将整个表单传递到下一个页面。因为我不想让用户再看到那个表单,所以我把它放在一个隐藏的 div 中。我从表单渲染图像并使用 JavaScript,在用户单击的位置绘制圆圈。当提交按钮被按下时,它会在脚本中运行一个函数,该函数第二次提交表单,但在提交之前用所有圆圈的位置更新 JSONField。

下面的代码在提交表单之前一直有效,但是当我到达 view2 函数时,form.is_valid() 总是返回 false。我怀疑问题出在这里

document.getElementById("id_spots").innerHTML = spot

我认为由于 Django 表单字段是一个 JSONField,我可以将 innerHTML 指定为我在 JavaScript 中创建的点对象。如果我看看这如何影响 HTML,[object Object] 被插入到点文本区域框中。我也试过 JSON.stringify(spots) 但无济于事。

谁能发现这个问题?是否有更好的方法来分配 JSONFiled 的值以匹配 django 中的变量?

views.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,{'form':form,'base':base})

models.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

forms.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 %}

解决方法

使用 JSON.stringify() 实际上是正确的方法:

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

我认为这部分是错误,因为我在提交表单时遇到错误,而表单中唯一更改的部分是 JSONField。实际上,错误似乎来自 ImageField。事实证明,如果您将表单作为上下文传递给另一个页面,则不会保留 ImageFields。

我发表了一篇关于 ImageField 问题的更相关的帖子,所以任何新的答案都应该重定向到这篇文章: How to pass image file from one page to another in multi-page form (Django)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。