I am running Django 2.2 and have written a simple shopping cart. I wish to validate two fields at the same time in such a way that both cannot be empty at the same time. In my forms.py,
from django import forms
class CartAddProductForm(forms.Form):
cc_handle = forms.CharField(required=False, label='CC Handle', empty_value='')
lc_handle = forms.CharField(required=False, label='LC Handle', empty_value='')
def clean(self):
cleaned_data = super().clean()
if cleaned_data.get('cc_handle') == '' and cleaned_data.get('lc_handle') == '':
print("issue detected")
raise forms.ValidationError('Either cc or lc handle is required.')
return cleaned_data
This is following the official Django docs on cleaning and validating fields that depend on each other. The print() statement above lets me know that the issue has been detected, i.e. both fields are empty. Running the Django server, I see that the issue was indeed detected but no validation error message was displayed on top of the originating page. The originating page is the product page that contains the product and a link to add the product to the shopping cart. Normally the validation error message is displayed at the top of the page.
According to the docs, the validation is done when is_valid() is called. So I put a diagnostic print of my views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views.decorators.http import require_POST
from shop.models import Product
from .cart import Cart
from .forms import CartAddProductForm
@require_POST
def cart_add(request, product_id):
cart = Cart(request)
product = get_object_or_404(Product, id=product_id)
form = CartAddProductForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
cart.add(product=product,
cc_handle=cd['cc_handle'],
lc_handle=cd['lc_handle'])
else:
print('invalid form')
return redirect('cart:cart_detail')
And indeed the words 'invalid form' popped up. The code then takes me to the shopping cart. Instead, what I want is to be at the product page and show the validation error informing the reader that both fields cannot be empty. Is there a simple way of doing it?
For required=True fields in the forms, if I leave it blank, there will be a message popping up saying that I need to fill it in. So I want to do something similar except the validation requires that both fields cannot be empty.
This is different from this Stackoverflow answer because that is a registration form. You can redirect it to the same form whereas for this case, the CartAddProductForm is embedded in all the products page on the site. If possible, I want the validation to occur at the same stage as the field with required=True option.
The product/detail.html template looks like the following.
{% extends "shop/base.html" %}
{% load static %}
{% block title %}
{{ product.name }}
{% endblock %}
{% block content %}
<div class="product-detail">
<img src="{% if product.image %}{{ product.image.url }}{% else %}{% static "img/no_image.png" %}{% endif %}">
<h1>{{ product.name }}</h1>
<h2><a href="{{ product.category.get_absolute_url }}">{{ product.category }}</a></h2>
<p class="price">${{ product.price }}</p>
<form action="{% url "cart:cart_add" product.id %}" method="post">
{{ cart_product_form }}
{% csrf_token %}
<input type="submit" value="Add to cart">
</form>
{{ product.description|linebreaks }}
</div>
{% endblock %}