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?
You need to pass the data, so:
form = CartAddProductForm(
instance=product,
pk=product_id,
data=request.POST,
)