从同一页面的多种表单获取用户输入

时间:2019-01-03 05:06:18

标签: python django django-forms

我正在使用Django Web应用程序。该应用程序在同一页面中包含两种形式。第一种形式用于上传图像,第二种形式用于图像描述。用户上传图像并单击“上传图像”按钮后,图像分类器应对图像进行分类并自动填充第二个表单的某些部分。

到目前为止,这是我的代码

models.py

class Item(models.Model):
    title = models.CharField(max_length=100)
    color = models.CharField(max_length=100)
    img = models.ImageField(upload_to='item/img/', null=False, blank=False)

    def __str__(self):
        return self.title

    def delete(self, *args, **kwargs):
        self.img.delete()
        super().delete(*args, **kwargs)

forms.py

from .models import Item

class ItemImage(forms.ModelForm):
    class Meta:
        model = Item
        fields = ('img',)

class ItemForm(forms.ModelForm):
    class Meta:
        model = Item
        fields = ('title', 'color')

views.py

from .forms import ItemForm, ItemImage
from .models import Item

def upload_item(request):
    if request.method == 'POST':
        form_img = ItemImage(request.POST, request.FILES)
        if form_img.is_valid():
            form_img.save()

        form_des = ItemForm(request.POST, request.FILES)
        if form_des.is_valid():
            form_des.save()
            return redirect('item_list')
    else:
        form_img = ItemImage()
        form_des = ItemForm()

    return render(request, 'upload_item.html', {'form_img': form_img, 'form_des': form_des})

upload_item.html模板

{% extends 'base.html' %}

{% load crispy_forms_tags %}

{% block title %} upload_item {% endblock title %}

{% block content %}
<div class="row justify-content-center">
  <div class="col-6">
    <h2>Upload item</h2>

    <div class="card mb-5 mt-1">
      <div class="card-body">
        <form method="post" enctype="multipart/form-data">
          {% csrf_token %}
          {{form_img|crispy}}
          <button type="submit" class='btn btn-primary'>upload img</button>
        </form>
      </div>
    </div>

    <div class="card mb-5 mt-1">
      <div class="card-body">
        <form method="post" enctype="multipart/form-data">
          {% csrf_token %}
          {{form_des|crispy}}
          <button type="submit" class='btn btn-primary'>Save item</button>
        </form>
      </div>
    </div>

  </div>
</div>

{% endblock content %}

我面临的问题是上传图像后,当我按“上传图像”按钮时,页面重新加载,我必须重新开始。我想当我按下按钮时,页面正在尝试保存表单。我该如何纠正?

[注意]我尚未编写图像分类代码。解决此问题后,我将在 views.py 中的 upload_item 函数下编写该代码

[编辑]

我对模板文件做了一些更改。现在,我可以上传图像并在图像上运行分类器。

这些是我所做的更改

upload_item.html模板

{% block content %}
<div class="row justify-content-center">
  <div class="col-6">
    <h2>Upload item</h2>

    <div class="card mb-5 mt-1">
      <div class="card-body">
        <form action="{{ request.build_absolute_uri }}image_classification/" method="POST" enctype="multipart/form-data">
          {% csrf_token %}
          <input id="search" , type="file" name="file"/>
          <input class='btn btn-primary' , type="submit" value="Upload image" />
        </form>
      </div>
    </div>

    <div class="card mb-5 mt-1">
      <div class="card-body">
        <form method="post" enctype="multipart/form-data">
          {% csrf_token %}
          {{form_des|crispy}}
          <button type="submit" class='btn btn-primary'>Save item</button>
        </form>
      </div>
    </div>

  </div>
</div>

{% endblock content %}

views.py

def handle_uploaded_file(file, filename):
    if not os.path.exists('media/classification/'):
        os.mkdir('media/classification/')

    with open('media/classification/' + filename, 'wb+') as destination:
        for chunk in file.chunks():
            destination.write(chunk)

def image_classification(request):

    form = ItemForm()

    cascade_path = "./classifier.h5"
    classifier = load_model(cascade_path)

    if request.method == 'POST':
        handle_uploaded_file(request.FILES['file'], str(request.FILES['file']))

        img = np.expand_dims(cv2.resize(cv2.imread(os.path.join('./media/classification/', str(request.FILES['file']))), (170, 100)), axis=0)
        pred_class = str(classifier.predict_classes(img)[0])
        print(pred_class)

        form.fields['title'].widget.attrs['value'] = pred_class
        return render(request, 'upload_item.html', {'form': form})

    return HttpResponse("Failed")

我添加了@Alexander Strakhov建议的代码。这就是我得到的结果。 enter image description here

我在做什么错了?

预先感谢

1 个答案:

答案 0 :(得分:1)

当您按下“上传图片”按钮时,您将请求发送到upload_item网址。那里您的意见:

1)将ItemImage表单绑定到request.Post(这是带有csrf令牌的QueryDict),并绑定到带有上传文件的request.FILES。

2)保存图像表格(假设图像有效)。

3)将ItemForm 绑定到与ItemImage相同的请求数据

4)再次在上下文中使用有界的form_img和form_des渲染upload_item.html。

咨询Django文档:https://docs.djangoproject.com/en/2.1/topics/forms/#the-view

按下“上传图片”时出现空白页面的原因是:

a)“标题”和“颜色”两个字段都绑定到QueryDict中的一个空值,因为按“上传图像”不会提交第二个表单,“标题”和“颜色”是其中的一部分。

b)似乎Django渲染回表格时没有将表格绑定到文件,而将表格留空(我会向社区咨询)。我建议在这里使用AJAX来验证您的图像并稍后运行分类。使用AJAX可以将图像保留在页面上,因为不会刷新页面,因此您以后可以使用“保存项目”按钮提交这两种表单。

修改

看到更新的代码后,我建议初学者进行以下操作:

替换def webhook(): data = request.get_json() log(data) if data['object'] == 'page': for entry in data['entry']: for messaging_event in entry['messaging']: sender_id = messaging_event['sender']['id'] recipient_id = messaging_event['recipient']['id'] if messaging_event.get('message'): if 'text' in messaging_event['message']: messaging_text = messaging_event['message']['text'] else: messaging_text = 'no text' response = None entity, value = wit_response(messaging_text) if entity == 'newstype': response = "OK. I will send you {} news".format(str(value)) elif entity == 'cust_greet': response = get_message() elif entity == 'cust_greet2': response = get_message2() elif entity == 'cust_offer': #response = offer_response response = " Generic Offer 1"+"\n"+" Generic Offer 2"+"\n"+" Generic Offer 3"+"\n"+" ️ for more offer enter your cust id" #val_off = test.val_off bot.send_text_message(sender_id, response)

使用

form.fields['title'].widget.attrs['placeholder'] = pred_class