如何在Django 1.6中使用ModelForms避免“记录已存在”的表单验证错误?

2 投票
1 回答
1515 浏览
提问于 2025-04-18 18:00

根据ModelForm的文档,我使用了这个模型:

class ShippingLabel(models.Model):
"""Record what shipping lables were printed list"""
class Meta:
    db_table = 'shipping_labels'
    ordering = ('client',)
    verbose_name = _('shipping label')
    verbose_name_plural = _('shipping labels')

LAYOUT_LASER_2x2 = "1"
LAYOUT_TICKET = "2"
LAYOUT_LASER_1x1 = "3"
LAYOUT_CHOICES = (
    ( LAYOUT_LASER_1x1, _("Laser (1x1 sheet)") ),
    ( LAYOUT_LASER_2x2, _("Laser (2x2 sheet)") ),
    ( LAYOUT_TICKET, _("Ticket (3-inch wide)") ),
)

client = models.ForeignKey(Company, blank=False, null=False, unique=True, help_text=_("Which Client to ship to?"), verbose_name=_("client") )
store = models.ForeignKey(Store, blank=False, null=False, help_text=_("What store info should be used? (address, logo, phone, etc)"), verbose_name=_("store") )
packages = models.CharField(_("Packages"), max_length=30, blank=False, null=False, help_text=_("Total number of packages. One label printed per package.") )
preprinted_form = models.BooleanField(_("Pre-Printed Form"), default=False, help_text=_("Are you using pre-printed shipping label stickers?"), )
layout = models.CharField(_("Record Type"), max_length=10, blank=False, null=False, choices=LAYOUT_CHOICES, default=LAYOUT_LASER_1x1, help_text=_("Print on large labels (4 per Letter page), Laser large labels (1 per page), or ticket printer?") )
added_by = models.CharField(_("Added By"), max_length=30, blank=True, null=True, help_text=_("The User that created this order.") )
date_added = models.DateTimeField(_('Date added'), auto_now_add=True)
date_modified = models.DateTimeField(_('Date modified'), auto_now=True)

def get_absolute_url(self):
    return reverse('shipping:printship', args=[str(self.id)])

def __unicode__(self):
    return unicode(self.client)

我按照他们的例子做了这个表单模板(manual_label.html):

{% extends "admin/base_site.html" %}
{% load i18n %}
{% load staticfiles %}

{% block extrahead %}
    {{ block.super}}
    <script src="{{ STATIC_URL }}js/jquery-1.11.1.js"></script>
{% endblock %}

{% block content %}
<form id="manual_label" method="post" action="">
    {% csrf_token %}
    {% for hidden in form.hidden_fields %}
        {{ hidden }}
    {% endfor %}
    <table>
        {{ form.as_table }}
    </table>
    <input type="submit" value="generar etiquetas autoadhesivas"/>
</form>
<p>

</p>
{% endblock %}

我的应用的urls.py文件是:

from django.conf.urls import patterns, url

from shipping.views import printship, pcustomer, manual_label

urlpatterns = patterns('',
    url(r'pcust/', pcustomer, name='pcustomer'),
    url(r'mlabel/([0-9]+)/$', manual_label, name='manual_label'),
    url(r'printlabel/([0-9]+)/$', printship, name='printship'),
)

我的视图(包含很多调试日志):

@login_required()
def manual_label(request, id):
    logger.debug("SHIPPING.VIEWS.manual_label")
    if request.method == 'POST':
        logger.debug("SHIPPING.VIEWS.manual_label: POST!")
        client = get_object_or_404(Company, pk=id)
        labelset = ShippingLabel.objects.filter(client=client)
        if len(labelset)>0:
            # Pre-existing label, update it:
            logger.debug("SHIPPING.VIEWS.manual_label.POST: Update a label!")
            label = labelset[0]
            form = ShipLabelForm(request.POST, instance=label)
        else:
            # New label:
            logger.debug("SHIPPING.VIEWS.manual_label.POST: Save New label!")
            form = ShipLabelForm(request.POST)
        if form.is_valid():
            logger.debug("SHIPPING.VIEWS.manual_label.POST: form is valid")
            label = form.save(commit=True)
            logger.debug("SHIPPING.VIEWS.manual_label.POST: label pk: " + str(label.id) )
            logger.debug("SHIPPING.VIEWS.manual_label.POST: label client name: " + str(label.client.name) )
            logger.debug("SHIPPING.VIEWS.manual_label: post return")
            return HttpResponseRedirect(reverse('shipping:printship', args=[str(label.id)]))
    else:
        logger.debug("SHIPPING.VIEWS.manual_label: GET!")
        client = get_object_or_404(Company, pk=id)
        labelset = ShippingLabel.objects.filter(client=client)
        if len(labelset)>0:
            # Pre-existing label, load it:
            logger.debug("SHIPPING.VIEWS.manual_label: Pre-Existing label, load it...")
            label = labelset[0]
            form = ShipLabelForm(instance=label)
        else:
            # New label:
            label = ShippingLabel(client=client,
                                store=request.user.employee.store,
                                added_by=request.user.get_username())
            form = ShipLabelForm(instance=label)
    logger.debug("SHIPPING.VIEWS.manual_label: get return")
    return render(request, 'shipping/manual_label.html', {
                                             'title': u"Creación de etiquetas Manual Envios",
                                             'form': form,
                                             })

我的forms.py定义是:

class ShipLabelForm(ModelForm):
    class Meta:
        model = ShippingLabel
        localized_fields = '__all__'
        fields = '__all__'
        widgets = {
            'added_by': HiddenInput,
            'id': HiddenInput,
        }

我添加了'id': HiddenInput,,想要“强制”把记录的ID号发送到表单中,理论上认为我的错误是因为没有ID号,Django会在“添加”模式下进行验证,这样肯定会触发我在客户上设置的“唯一”标志。

manual_label视图是通过客户选择表单调用的,传入客户的ID。目标是如果当前没有为这个客户定义运输标签,就生成一个添加表单——这部分是正常工作的。

如果已经存在运输标签,我会预先加载表单的数据。我的想法是,表单系统会自动对现有记录进行更新。

无论哪种情况,保存的运输标签记录都会用来生成所需的运输标签。

在管理视图中(使用在网站上查看)这部分是可以正常工作的。但我想给用户一个更简单的系统。这对于添加新标签来说没问题。但是当我尝试编辑一个已有标签时,我遇到了表单验证错误“客户已存在

这看起来是个很简单的事情……

那么,我到底漏掉了什么或者做错了什么呢?

1 个回答

2

在初始化表单的时候,无论是处理提交的数据(POST)还是获取数据(GET),你都应该使用instance这个参数。

撰写回答