manderson
manderson

Reputation: 891

View didn't return an HttpResponse

My project is here github Project

I'm getting this error.

ValueError at /salesapp/add/ashton-aged-maduro/
The view salesapp.views.add_CartItem didn't return an HttpResponse object. It returned None instead. 

I get this error when I click the 'Add to Cart' button on my singleproduct.html template which calls the ProductAddToCart form. The view is add_CartItem.

I also get the error Field is required when I don't initially set the form values. I'm just stuck now.

This is models.py

class Product(models.Model):
    itemid = models.CharField(max_length=128, unique=True)
    itemname = models.CharField(max_length=128)
    brand = models.CharField(max_length=128)
    image = models.ImageField(upload_to='static/images/')
    notes = models.CharField(max_length=250)
    price = models.IntegerField()
    slug = models.SlugField(unique=True)

    def save(self, *args, **kwargs):
        self.slug = slugify(self.itemname)
        super(Product, self).save(*args, **kwargs)

    def __str__(self):
        return self.itemname

class CartItem(models.Model):
    cart_id = models.CharField(max_length=50)
    date_added = models.DateTimeField(auto_now_add=True)
    quantity = models.IntegerField(default=1)
    itemid = models.ForeignKey('Product', unique=False)

    class Meta:
        db_table = 'cart_items'
        ordering = ['date_added']

    def name(self):
        return self.product.name

My forms.py

 class ProductAddToCartForm(forms.ModelForm):
        cart_id = forms.CharField(max_length=50)
        date_added = forms.DateTimeField()
        quantity = forms.IntegerField()
        slug = forms.CharField(widget=forms.HiddenInput(), required=False)

        #itemid = models.ForeignKey('Product', unique=False)

        class Meta:
            model = CartItem
            fields = ('cart_id', 'date_added', 'quantity', 'slug', 'itemid', )

My views.py

def add_CartItem(request, product_name_slug):
        print('In add_CartItem --------------------')
    form = ProductAddToCartForm(request.POST)

    p = Product.objects.get(slug=product_name_slug)
    form = ProductAddToCartForm(initial={'cart_id': 123, 'date_added':date.date.today(), 'quantity': 1, 'slug':p.slug, 'id':p.id, 'itemid':p.itemid})
    form.save(commit=False)
    print(form)
    print(p.slug)
    print(p.id)
    print(p.itemid)

    if form.is_valid():
        print(p)
        print('In form.is_valid()--------------------------------')

        ci = CartItem.objects.create(cart_id=1, date_added=date.date.today(), quantity=1, itemid=p)

        form.save(commit=True)
        return index(request)
    else:
        print(form.errors) #return render(request, 'salesapp/errors.html', {'form': form})

My urls.py

from django.conf.urls import url
from salesapp import views

    urlpatterns = [
        url(r'^$', views.index, name='index'),
        url(r'about/', views.about, name='about'),
        url(r'customers/', views.customers, name='customers'),
        url(r'products/', views.products, name='products'),
        url(r'^add_product/$', views.add_product, name='add_product'),
        url(r'^add_customer/$', views.add_customer, name='add_customer'),
        url(r'items/(?P<product_name_slug>[\w\-]+)/$', views.show_product, name='show_product'),
        url(r'^add/(?P<product_name_slug>[\w\-]+)/$', views.add_CartItem, name='add_CartItem'),
        #url(r'^cart/$', views.show_cart, name='show_cart'),
        #url(r'^register/$', views.register, name='register'),
        #url(r'^login/$', views.user_login, name='login'),
        #url(r'^logout/$', views.user_logout, name='logout'),
        #url(r'^restricted/', views.restricted, name='restricted'),
    ]

and my template where I want to display the ProductAddToCartForm but add a product to the CartItem table.

<!DOCTYPE html>
{% extends 'salesapp/base.html' %}
{% load staticfiles %}

{% block title_block %}
    {{ product.itemname }}
{% endblock %}

{% block body_block %}

    <div>
        <div>
            <ul style="list-style:none; text-align:center;">
                <li style="float:left; width:25%; margin:20px;">
                        <img src="/{{ product.image }}"/>
                    <div>
                        <b>{{ product.itemname }}</b><br/>
                        Price per cigar:<br/>
                        <b>${{ product.price }}</b>
                        <p>{{ product.notes }}</p>
                    </div>

                    <form method="post" action="/salesapp/add/{{ product.slug }}/" class="cart">
                        {% csrf_token %}
                        {% for hidden in form.hidden_fields %}
                            {{ hidden }}
                        {% endfor %}
                        {% for field in form.visible_fields %}
                            {{ field.errors }}
                            {{ field.help_text }}
                            {{ field }}
                        {% endfor %}
                         <br />
                         <input type="submit" value="Add To Cart" name="submit" alt="Add To Cart" />
                    </form>
                    <div class="cb"></div>
                </li>
            </ul>
        </div>
    <!-- More code -->
    </div>

{% endblock %}

Upvotes: 1

Views: 2450

Answers (4)

Mauricio Cortazar
Mauricio Cortazar

Reputation: 4213

first delete the prints, almost when you make a question, are useless in Django

def add_CartItem(request, product_name_slug):
    form = ProductAddToCartForm(request.POST)

    if request.method == 'POST':
        if form.is_valid():    
            ci = CartItem.objects.create(cart_id=1, date_added=date.date.today(), quantity=1, itemid=p)
            ci.save()#you save your model changes, not your form
            return HttpResponseRedirect(reverse('your:url'))#your return the success url or the same
        else:
            #here error, if form isn't valid
    else:
        form = ProductAddToCartForm(request.POST)
        return render(request, 'your/template.html', {'form': form})

That is the correct way to work with forms in Django, first you must make a if statement asking to the browser if is a post request or a normal request, if is post request, take the data from the forms and are adding to the database, if not, Django return a empty template form.

Let me know if you problem solve

Upvotes: 1

echefede
echefede

Reputation: 536

A view function must return an HttpResponse. For example, if the process was successfull and you dont want to return anything, you can return HttpResponse(status=200)

When a view handles forms, you have to split GET and POST requests. In the GET part you need to instantiate the form without data. In the POST part you fill the form with request.POST data. And this data must have ALL mandatory fields. A typical view function scheme to handle a form is the folowing:

def view(request):
   if request.method == "GET":
       form = MyForm()
       return ...
   if request.method == "POST":
       form = MyForm(request.POST)
       form.save()
       return ...

In your template, you have to show all form fields. Then, all form fields will be passed with the request. If you dont, you need to fill the form fields in the view.

Upvotes: 1

Vasanth Kumar
Vasanth Kumar

Reputation: 371

A view function in django should either return a json or a dict or can return a Webpage You can either do one of following 1) return a json or dict

return {"value1":"value","value2":"value"}

2)redirect to a web page

return redirect('/some/url/')

3)return Http response

return HttpResponse(status=<status code>,content="some content")

4)render a template

t = loader.get_template('myapp/index.html')
c = {'foo': 'bar'}
return HttpResponse(t.render(c, request), 
content_type='application/xhtml+xml')

Upvotes: 3

Aniket Pawar
Aniket Pawar

Reputation: 2721

Because you did not return any response to the view,

According to the docs

A view function is simply a Python function that takes a Web request and returns a Web response.

You need to return to use render method for initial rendering of form and for redirection to another view you can use redirect method of Django.

Upvotes: 1

Related Questions