【问题标题】:Django- how to save form input to an object model in the database?Django-如何将表单输入保存到数据库中的对象模型中?
【发布时间】:2016-11-24 23:22:25
【问题描述】:

我有一个 Django 项目,用于管理多个项目以及与项目相关的所有信息。

在其中一个名为“概念”的网页上,有一个表单,它在一个文本框中输入不含增值税的成本值,在另一个文本框中显示含增值税的成本,并有一个datepicker 字段允许用户选择支付押金的日期(如果有的话)。

我在获取表单以保存用户输入的当前日期值时遇到了一些麻烦 - 如果用户填写表单中的三个字段(成本 exc 增值税 - 由用户输入,成本inc vat- 根据 const exc vat, & date) 自动生成,然后刷新页面,两个成本字段保留其值,但 'date' 字段恢复为空白。

当我检查“日期”字段的页面元素时,我可以看到它位于以下 HTML 结构中:

<body>
    ...
    <div class="wrapper">
        <div class="content">
            <form method="POST" .... data-view-url=".../concept_save_ajax/">
                <div class="col-12-box">
                    <div>
                        <table class="right fixed m-t-md">
                            <tbody>
                                <tr>
                                    ...
                                    <td class="p-r-md">Deposit exc VAT</td>
                                    <td class="p-r-md">
                                        <input class="currency" id="id_amount_exc_vat" name="amount_exc_vat" type="number" value="280">
                                    <td class="p-r-md>
                                        <input class="datepicker hasDatepicker" data-original-value id="id_date_received" name="date_received" type="text"> == $0
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </form>
        </div>
    </div>
</body>

编辑

虽然这是我在浏览器中检查时页面的 HTML 结构,但我的项目中 HTML 文件的实际代码是:

{% block content %}
    <form method="POST" enctype="multipart/form-data" data-vat-status="{{project.vat_status}}" data-view-url="{% url 'projects:concept_save_ajax_2' project.id %}" class="autosave_form formset full-width" action="{% url 'projects:upload_budget_pdfs' project.id %}">
        ...
    </form>
    <form method="POST" enctype="multipart/form-data" data-vat-status="{{project.vat_status}}" data-view-url="{% url 'projects:concept_save_ajax' project.id %}" class="autosave_form full-width">
        {% csrf_token %}

        <div class="col-12 box">
            <div>
                <table class="right fixed m-t-md">
                    <tr>
                        {% for hidden in deposit_form.hidden_fields %}
                            {{hidden}}
                        {% endfor %}
                        {% for field in deposit_form.visible_fields %}
                            <td class="p-r-md">{{field.label}}</td><td class="p-r-md">{{field}}</td>
                        {% endfor %}
                        <td><a class="email_trigger button" data-view-url="{% url 'comms:open_email_template' project.id %}?template=7">Raise invoice</a></td>
                    </tr>
                </table>
            </div>
        </div>
        <div class="col-6 box">
            ...
        </div>
        <div class="col-6 box">
            ...
        </div>
    </form>

{% endblock content %}

结束编辑

鉴于表单方法指定为POST,我希望使用concept_save_ajax 视图保存输入表单的信息,如开头&lt;form&gt; 标记内所示。

此视图在views.py 中定义:

def concept_save_ajax(request, project_id):
""" Save concept forms """
if not request.is_ajax():
    raise Http404('Ajax only')

if request.method == 'POST':
    project = Project.objects.prefetch_related('budget_versions', 'budget_overview').get(pk=project_id)

    form_instances = [
        # [DepositForm, project.deposit],
        [DepositInfoForm, project.deposit],
        [BudgetNotesForm, project.budget_overview],
        [EndDetailsForm, project.end],
    ]

    # Save the forms 
    for form_instance in form_instances:
        form = form_instance[0](request.POST, instance=form_instance[0]) #1]) should be '0' for first element?
        if form.is_valid() and form.has_changed():
            print form_instance[0], "is valid.", form_instance[0]
            updated_details = form.save()
        elif form.has_changed():
            print form_instance[0], "is not valid", form.errors
            return JsonResponse({'error': form.errors})



    # url = '/projects/{0}/?tab={1}'.format(project_id, tabs[3])
    return JsonResponse({'success': 'Saved'})
else:
    raise Http404('Request is not a post')

我可以看到,如果满足条件 form.is_valid()form.has_changed() 时,此视图正在调用 form.save(),但由于某种原因,当我为 ' 输入新值时,这似乎并没有实际保存日期”字段。

我已尝试在控制台中对此进行测试 - 但应保存“日期”值的字段似乎为空...在控制台中,我运行了:

 from projects import models

 from projects.models import Project

 allPrjcts = Project.objects.all()

 br = allPrjcts.filter(project_name="1 Brocks Road")

 from costing import models

 from costing.models import Deposit

 allDpsts = Deposit.objects.all()

 brocksRoad = br[0]          # I know that this is the only project returned by the filter

brDpst = allDpsts.get(project_id = 6311L)      # I know that this is the ID for the 'brocksRoad' project

然后,当我在控制台中运行brDpst.date_received时,什么都没有显示,表明我在网页上的“日期”字段中输入的值似乎没有被保存...

有什么想法吗?如何获取“日期”字段的值以自动保存,以便在我重新加载页面时显示,与该表单上的“成本”字段相同?

如果我在控制台中运行brDpst.amount_exc_vat,它会显示值:

十进制('280.00')

这是我在文本框中输入的金额,所以很明显表单正在保存......只是由于某种原因,“日期”字段的值没有被保留......

编辑

DepositInfoForm 当前是这样定义的:

class DepositInfoForm(ValidatedForm):
    ...
    date_received = MoonDateField(required=False, label="Date deposit received", widget=forms.DateInput(format='%d/%m/%Y', attrs=({'class':'datepicker'})))

我尝试将其更改为:

class DepositInfoForm(ValidatedForm):
    ...
    date_received = MoonDateField(required=False, label="Date deposit received", widget=forms.DateInput(format='%d/%m/%Y', attrs=({'class':'datepicker', 'type':'date'})))

正如@neverwalkaloner 所建议的那样,但如果我这样做,当我选择表单上的date_received 字段时,下拉菜单中会显示两个日历...我想使用已经存在的日历可供选择日期,而不是我传递给date_received 变量的'type':'date' 参数添加的日期...

编辑

我已经为我的DepositInfoForm(...) 类添加了一些调试,似乎当对采用数值的表单字段进行更改时,它的save() 方法正在被调用,但save() 没有被调用当对包含日期的表单字段进行更改时...我不明白这是为什么...?

DepositInfoForm(...) 类定义为:

class DepositInfoForm(ValidatedForm):
    amount_exc_vat = forms.IntegerField(required=False, widget=forms.NumberInput(attrs={'class': 'currency',}),label="Deposit exc VAT")
    amount_inc_vat = forms.IntegerField(required=False, widget=forms.NumberInput(attrs={'class': 'currency', 'readonly':'readonly',}),label="Inc VAT")
    date_received = MoonDateField(required=False, label="Date deposit received", widget=forms.DateInput(format='%d/%m/%Y', attrs=({'class':'datepicker'})))

    class Meta:
        model = Deposit
        fields = ('amount_exc_vat', 'amount_inc_vat', 'date_received')#,'received')

    def __init__(self, *args, **kwargs):
        print "__init__ method being called in DepositInfoForm"
        instance = kwargs.get('instance', {})
        project = instance.project

        try: amount_exc_vat = int(round(instance.amount_exc_vat))
        except TypeError: amount_exc_vat = None
        try: amount_inc_vat = int(round(project.deposit.amount_inc_vat))
        except TypeError: amount_inc_vat = None

        try: date_received = instance.date_received
        except TypeError: date_received = None

        initial = kwargs.get('initial', {})
        initial={
                    'received': project.deposit_received,
                    'amount_exc_vat': amount_exc_vat,
                    'amount_inc_vat': amount_inc_vat,
                    'date_received': date_received,
                }
        kwargs['initial'] = initial

        super(DepositInfoForm, self).__init__(*args, **kwargs)
        self.fields['date_received'].widget.attrs.update({'data-original-value': self.initial['date_received'] or ''})

    def save(self, commit=True):
        print "Save method being called in DepositInfoForm"
        deposit = self.instance
        data = self.cleaned_data

        print "save method being called in DepositInfoForm (projects/forms.py line 1142)"
        if 'date_received' in self.changed_data:
            if not data['date_received'] == '':
                deposit.project.deposit_received = True;
                self.deposit_r = True
                deposit.project.upgrade_detailed_status(Project.ds75)
        else:
            deposit.project.deposit_received = False;       
        deposit.project.save()

        if ('amount_exc_vat' in self.changed_data or 'date_received' in self.changed_data in self.changed_data) and data['amount_exc_vat'] and data['date_received']:
            send_message(message_template=2, project=self.instance.project)
            self.deposit_r = True       

        if hasattr(self, 'deposit_r'):
            # Make the payment
            deposit_payment = Payment(project=deposit.project, is_booking_deposit=True, amount_exc_vat=data['amount_exc_vat'], date_paid=data['date_received'])

        return super(DepositInfoForm, self).save(commit=commit)

编辑

当我尝试更改网页上表单中的日期时,虽然最初显示的是新日期,但如果我刷新页面,它的值会变回我更改之前的值。当我更改表单中“日期”字段的值时,控制台显示以下输出:

 Exception in thread Thread-42:
Traceback (most recent call last):
  File ".../threading.py", line 810, in __bootstrap_inner
self.run()
  File ".../models.py", line 138, in run
msg.send(self.fail_silently)
  File ".../message.py", line 292, in send
return self.get_connection(fail_silently).send_messages([self])
  File ".../smtp.py", line 100, in send_messages
new_conn_created = self.open()
  File ".../smtp.py", line 67, in open
self.connection.login(self.username, self.password)
  File ".../smtplib.py", line 615, in login
raise SMTPAuthenticationError(code, resp)
SMTPAuthenticationError: (535, '5.7.3 Authentication unsuccessful')

但我实际上并没有更改它在Traceback 中抱怨的任何文件...是什么导致了这个异常?

【问题讨论】:

  • 您需要显示表单的代码,以及您提交的数据的格式。
  • 我已经编辑了我的 OP 以显示表单的定义。

标签: python django forms


【解决方案1】:

可能是因为 date_received 的 type=text 而不是 type=date。 尝试更改您的表单:

class DepositInfoForm(forms.Form):
    date_received = forms.DateField(widget=forms.TextInput(attrs=
                            {
                                'class':'datepicker hasDatepicker',
                                'type':'date'  
                            })

【讨论】:

  • 因为 HTML 是用 Django 编写的,而不是普通的 HTML,我无法访问表单中的各个元素...所以我不确定如何更改 @987654322 @ 为表单上的这个元素?我已经更新了我的 OP 以在 HTML 文件中显示 Django 代码。
  • @someone2088 查找 DepositInfoForm 类的代码并尝试按照我的回答更改 date_received 字段。
  • date_received 字段在表单中定义为:date_received = mDateField(required=False, label="Date deposit received", widget=forms.DateInput(format='%d/%m/%Y', attrs=({'class':'datepicker'}))),即它目前没有type 属性...
  • @someone2088 尝试添加它。
  • 我尝试添加它,但是当我查看页面时,当我选择该输入字段时,我会在下拉列表中显示两个不同的日历......我希望我想使用最初存在的那个,而不是我通过添加'type':'date'添加的那个...
猜你喜欢
  • 2021-06-28
  • 1970-01-01
  • 2021-09-15
  • 2023-03-28
  • 2021-01-01
  • 1970-01-01
  • 2021-05-03
  • 2015-07-07
  • 1970-01-01
相关资源
最近更新 更多