1

I've looked through a bunch of the other posts - but I can't find anything quite fitting to my scenario. I've got a bit of data that is coming across in the POST but then when I save the form - the data is not appearing in the database.

I'm a bit perplexed as to why this is and I've tried various things, but none of them really seem to apply to my situation. Most have to do with the data not being posted, my data is posted, it's just not saving.

I've got the following model:

class Payment(models.Model):
    METHODS = (
        ("Cash", "Cash"),
        ("Check", "Check"),
        ("Credit Card", "Credit Card")
    )
    amount = models.DecimalField(decimal_places=2, max_digits=6)
    method = models.CharField(
        max_length=15,
        choices=METHODS,
        default="Credit Card"
    )
    stripe_id = models.CharField(max_length=255, blank=True, null=True)
    check_number = models.IntegerField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

Here is my PaymentForm:

class PaymentForm(forms.ModelForm):
    method = forms.CharField(
        max_length=25,
        widget=forms.TextInput(attrs={
            "class": "form-control",
            "readonly": "True",
            })
        )
    amount = forms.DecimalField(
        decimal_places=2,
        max_digits=6,
        widget=forms.TextInput(attrs={
            "class": "form-control",
            "readonly": "True",
            })
        )
    stripe_id = forms.CharField(
        widget=forms.HiddenInput(),
        required=False
    )
    check_number = forms.IntegerField(
        widget=forms.TextInput(attrs={"class": "form-control"}),
        required=False
    )

    class Meta:
        model = Payment
        fields = (
            'amount',
            'method',
            'stripe_id',
            'check_number',
        )

    def clean_check_number(self):
        method = self.cleaned_data["method"]
        check_number = self.cleaned_data["check_number"]
        if method == "Check" and not check_number:
            raise forms.ValidationError("Check number is required.")

Here is my view.py function that relates to the POST:

    if request.method == "POST":
        # Create a copy of the POST data so we can input data for CC payments
        post_data = request.POST.copy()
        # Set the PaymentForm with the copied data (muteable)
        # required for some of the stripe stuff we do
        payment_form = PaymentForm(post_data)

        if 'stripeToken' in request.POST:
            # This is wrapped in extensive try/catch in reality but I left
            # it out for brevity
            charge = stripe.Charge.create(
                amount=stripe_cost,
                currency="usd",
                description="Payment",
                source=request.POST["stripeToken"],
                receipt_email=request.POST["stripeEmail"],
            )
            # add things to the form that aren't there
            # from the stripe reply
            payment_form.data['method'] = "Credit Card"
            payment_form.data['stripe_id'] = charge["id"]
            # This part works fine
        if payment_form.is_valid():
            # either a non-stripe payment
            # or the next step after the stripe stuff is don
            payment_form.save(commit=False)
            print(payment_form.data)
            payment = payment_form.save()
            # The data saves to the DB, but the check_number is empty!
        messages.success(request, "Thank you for your payment!")
        return redirect("my_app:index") 

That print statement after the form is valid prints out like this:

<QueryDict: {'csrfmiddlewaretoken': ['3blahblahblah'], 'amount': ['9.10'], 'method': ['Check'], 'check_number': ['123455'], 'stripe_id': ['']}>

The issue I'm having is this: when a user selects Check as payment and saves the payment (with a check number) the check number isn't saving to the database.

As we can see, the request.POST data shows all the data there (including check number) - but in the database the check_number is not being stored when the .save() is running.

What might make that happen and how do I ammend that?

6
  • What happens if you remove check_number = forms.IntegerField( .... ) from the form and you just use the default model form implementation of the field? Commented Oct 25, 2019 at 13:48
  • The check_number still comes across in request.POST - but does not save to the database. Commented Oct 25, 2019 at 13:54
  • And you have run your latest migrations? Commented Oct 25, 2019 at 13:55
  • Yes, all migrations are up to date. Commented Oct 25, 2019 at 13:56
  • Hmmm, and if you remove the blank=True, null=True in the model and then create a run a new migration? Besides that I have no idea... Commented Oct 25, 2019 at 13:59

1 Answer 1

2

You should be printing form.cleaned_data, not form.data, after the is_valid. If you did, you would see that check_number is empty. The reason for that is that you don't return anything from your clean_check_number method. You always need to return the cleaned value from those methods.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.