1

我遇到了一个问题,我在视图函数的 GET 部分中使用模型的预先存在的实例来实例化基于 ModelForm 的表单。该模型已经填写了几个字段;ModelForm 用于收集模型中的其他字段。ModelForm 的定义中排除了预先存在的字段。

问题是,在 POST 处理期间,在成功验证 ModelForm 后,我调用 ModelForm.save(commit=False)...并返回模型(这应该与我在GET 处理,记住)以某种方式丢失了之前设置的所有字段。表单实际设置的字段没问题;但它不再是我模型的原始实例。

这不是我所期望的行为;事实上,我以前使用过这种部分模型形式的模型,它在其他地方也可以使用。我在这里想念什么?

希望一些代码会让这一切变得清晰......

所以这里是模型:

class Order(models.Model):

    STATUS = (
       ('Created', -1),
       ('Pending', 0),
       ('Charged', 1),
       ('Credited', 2),
    )

    SHIPPING_STATUS = (
       ('Cancelled', 0),
       ('Ready for pickup', 1),
       ('Shipped', 2),
       ('OTC', 3),
    )

    orderID = models.IntegerField(max_length=15, null=True, blank=True)
    store = models.ForeignKey(Store)
    paymentInstrument = models.ForeignKey(PaymentInstrument, null=True, blank=True)
    shippingMethod = models.ForeignKey(ShippingMethod, null=True, blank=True)

    last_modified = models.DateTimeField(null=True, blank=True)
    date = models.DateTimeField(auto_now_add=True, null=True, blank=True)

    total = models.FloatField(default=0.0, blank=True)
    shippingCharge = models.FloatField(default=0.0, blank=True)
    tax = models.FloatField(default=0.0, blank=True)

    status = models.CharField(max_length=50, choices=STATUS, default = 'Created')
    shippingStatus = models.CharField(max_length=50, choices=SHIPPING_STATUS, default = '1')

    errstr = models.CharField(max_length=100, null=True, blank=True)

    #  billing info
    billingFirstname = models.CharField(max_length = 50, blank = True)
    billingLastname = models.CharField(max_length = 50, blank = True)
    billingStreet_line1 = models.CharField(max_length = 100, blank = True)
    billingStreet_line2 = models.CharField(max_length = 100, blank = True)
    billingZipcode = models.CharField(max_length = 5, blank = True)
    billingCity = models.CharField(max_length = 100, blank = True)
    billingState = models.CharField(max_length = 100, blank = True)
    billingCountry = models.CharField(max_length = 100, blank = True)

    email = models.EmailField(max_length=100, blank = True)
    phone = models.CharField(max_length=20, default='', null=True, blank=True)

    shipToBillingAddress = models.BooleanField(default=False)

    #  shipping info
    shippingFirstname = models.CharField(max_length = 50, blank = True)
    shippingLastname = models.CharField(max_length = 50, blank = True)
    shippingStreet_line1 = models.CharField(max_length = 100, blank = True)
    shippingStreet_line2 = models.CharField(max_length = 100, blank = True)
    shippingZipcode = models.CharField(max_length = 5, blank = True)
    shippingCity = models.CharField(max_length = 100, blank = True)
    shippingState = models.CharField(max_length = 100, blank = True)
    shippingCountry = models.CharField(max_length = 100, blank = True)

这是 ModelForm 的定义:

class OrderForm(ModelForm):

   class Meta:
      model = Order
      exclude = ('orderID',
                 'store', 
                 'shippingMethod', 
                 'shippingStatus', 
                 'paymentInstrument',
                 'last_modified',
                 'date',
                 'total',
                 'payportCharge',
                 'errstr',
                 'status', )
      widgets = {
          'billingCountry': Select(choices = COUNTRIES, attrs = {'size': "1"}),
          'shippingCountry': Select(choices = COUNTRIES, attrs = {'size': "1"}),
          'billingState': Select(choices = STATES, attrs = {'size': "1"}),
          'shippingState': Select(choices = STATES, attrs = {'size': "1"}),
                 }

这是视图功能:

def checkout(request):

    theDict = {}

    store = request.session['currentStore']
    cart = request.session.get('cart', False)
    order = request.session['currentOrder'] # some fields already set
    if not cart:   # ...then we don't belong on this page.
        return HttpResponseRedirect('/%s' % store.urlPrefix)

    if request.method == 'GET':

        form = OrderForm(instance=order, prefix='orderForm')

    else:    # request.method == 'POST':
        logging.info("Processing POST data...")

        form = OrderForm(request.POST, prefix='orderForm')

        if form.is_valid():
            ### AT THIS POINT, ORDER FIELDS ARE STILL GOOD (I.E. FILLED IN)
            order = form.save(commit=False)
            ### AFTER THE SAVE, WE'VE LOST PRE-EXISTING FIELDS; ONLY ONES SET ARE
            ### THOSE FILLED IN BY THE FORM.

            chargeDict = store.calculateCharge(order, cart)

            request.session['currentOrder'] = order

            return HttpResponseRedirect('/%s/payment' % store.urlPrefix)

        else:  
            logging.info("Form is NOT valid; errors:")
            logging.info(form._errors)

            messages.error(request, form._errors)

    theDict['form'] = form
    theDict['productMenu'] = buildCategoryList(store)

    t = loader.get_template('checkout.html')
    c = RequestContext(request, theDict)

    return HttpResponse(t.render(c))

任何/所有帮助表示赞赏...

4

1 回答 1

1

当您在 POST 期间实例化表单时,您正在编辑的模型实例为 None,因为您没有将其传入,也没有从 GET 中持久化表单实例。Django 不会自己做任何事情来为您保留请求之间的数据。

尝试:

...

form = OrderForm(request.POST or None, instance=order, prefix='orderForm')

if request.method == 'POST':
    logging.info("Processing POST data...")

    if form.is_valid():
        ...

现在该实例将为 GET 和 POST 填充,但来自 request.POST 的数据对于表单来说是可选的,如果它是无的话。它还使您不必在两个地方实例化表单,具体取决于request.method

于 2013-07-24T16:03:53.187 回答