I do my own project and I'm stuck on this problem. My form always returns False when calling form.is_valid.
This is my code:
forms.py:
I need to let user to choose the size he need from the list of available sizes, so I retrieve sizes from the database and then make a ChoiceField with variants of these sizes.
class CartAddProductForm(ModelForm):
class Meta:
model = Product
fields = ['sizes']
def __init__(self, pk: int, *args, **kwargs) -> None:
super(CartAddProductForm, self).__init__(*args, **kwargs)
sizes = tuple(Product.objects.get(pk=pk).sizes)
sizes_list = []
for item in sizes:
sizes_list.append((item, item))
self.fields['sizes'] = forms.ChoiceField(choices=sizes_list)
views.py:
This func creates the form
def product_detail(request: WSGIRequest, product_id: int, product_slug: str) -> HttpResponse:
product = get_object_or_404(Product,
id=product_id,
slug=product_slug,
available=True)
categories = Category.objects.all()
cart_product_form = CartAddProductForm(instance=product, pk=product_id)
return render(request, 'shop/product/detail.html', {'product': product,
'categories': categories,
'cart_product_form': cart_product_form})
When user pushes the button 'Add to cart' he is redirected to the other page with details of his cart. So here's the problem:
@require_POST
def add_to_cart(request: WSGIRequest, product_id: int) -> HttpResponseRedirect:
cart = Cart(request)
product = get_object_or_404(Product, id=product_id)
form = CartAddProductForm(instance=product, pk=product_id)
if form.is_valid():
cd = form.cleaned_data
print(f'cd = {cd}')
cart.add(product=product,
quantity=cd['quantity'],
update_quantity=cd['update'])
else:
print(f'form.is_valid = {form.is_valid()}')
print(f'request.POST = {request.POST}')
print(f'form.errors = {form.errors}')
print(f'form.non_field_errors = {form.non_field_errors}')
field_errors = [(field.label, field.errors) for field in form]
print(f'field_errors = {field_errors}')
return redirect('cart:cart_detail')
my template:
{% extends "shop/base.html" %}
<head>
<meta charset="UTF-8">
<title>Detail</title>
</head>
<body>
{% block title %}
{{ product.name }}
{% endblock %}
{% block content %}
<br>
<b>{{ product.name }} </b> <br>
<i>{{ product.description }} </i> <br>
{{ product.price }} <br>
<img src="{{ product.image.url }}" width="300" height="500"> <br>
Доступные размеры: <br>
{{ product.sizes }}<br>
<form action="{% url "cart:add_to_cart" product.id %}" method="post">
{{ cart_product_form }}
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Add to cart">
</form>
{% endblock %}
</body>
urls.py:
urlpatterns = [
re_path(r'^$', views.cart_detail, name='cart_detail'),
re_path(r'^add/(?P<product_id>\d+)/$', views.add_to_cart, name='add_to_cart'),
re_path(r'^remove/(?P<product_id>\d+)/$', views.cart_remove, name='cart_remove'),
]
I tried to print errors but got nothing:
print(f'form.is_valid = {form.is_valid()}')
print(f'request.POST = {request.POST}')
print(f'form.errors = {form.errors}')
print(f'form.non_field_errors = {form.non_field_errors}')
field_errors = [(field.label, field.errors) for field in form]
print(f'field_errors = {field_errors}')
output:
form.is_valid = False
request.POST = \<QueryDict: {'sizes': \['S'\], 'csrfmiddlewaretoken': \['mytoken'\]}\>
form.errors =
form.non_field_errors = \<bound method BaseForm.non_field_errors of \<CartAddProductForm bound=False, valid=False, fields=(sizes)\>\>
field_errors = \[('Sizes', \[\])\]
Also I have to say that after redirection to the cart page there are no detail on it, it's empty and no items there. What's wrong and why my form returns False?