NoReverseMatch Error in django while creating shopping cart app - python

Getting error NoReverseMatch
Reverse for 'add_to_cart' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['cart/(?P<slug>[\\w-]+)/']
urls.py
url(r'^cart/(?P<slug>[\w-]+)/', views.add_to_cart, name='add_to_cart'),
views.py
from django.core.urlresolvers import reverse
def add_to_cart(request, slug):
request.session.set_expiry(120000)
try:
the_id = request.session['cart_id']
except:
new_cart = Cart()
new_cart.save()
request.session['cart_id'] = new_cart.id
the_id = new_cart.id
cart = Cart.objects.get(id=the_id)
try:
product = Product.objects.get(slug=slug)
except Product.DoesNotExist:
pass
except:
pass
product_var = [] #product variation
if request.method == "POST":
qty = request.POST['qty']
for item in request.POST:
key = item
val = request.POST[key]
try:
v = Variation.objects.get(product=product, category__iexact=key, title__iexact=val)
product_var.append(v)
except:
pass
cart_item = CartItem.objects.create(cart=cart, product=product)
if len(product_var) > 0:
cart_item.variations.add(*product_var)
cart_item.quantity = qty
cart_item.save()
# success message
return HttpResponseRedirect(reverse("cart"))
#error message
return HttpResponseRedirect(reverse("cart"))
prod.html
<form class='form' method='POST' action='{% url "add_to_cart" product.slug %}'> {% csrf_token %}
<input class='btn btn-default btn-block' type='submit' value='Add to cart'/>
<input class="form-control" name='qty' type='number' value='1'/>
{% if product.variation_set.all %}
{% if product.variation_set.sizes %}
<select class='form-control' name='size'>
{% for item in product.variation_set.sizes %}
<option value='{{ item.title|lower }}'>{{ item.title|capfirst }}</option>
{% endfor %}
</select>
{% endif %}
{% if product.variation_set.colors %}
<select class='form-control' name='color'>
{% for item in product.variation_set.colors %}
<option value='{{ item.title|lower }}'>{{ item.title|capfirst }}</option>
{% endfor %}
</select>
{% endif %}
{% endif %}
</form>
I think i am missing something. Even if I mention other url name it displays the same error with that url pattern. Do i have to import something which can resolve it.

You haven't shown the view responsible for rendering prod.html in the first place. But it is clear from the error that the object you are passing as product to that template has an empty string for its slug attribute.

From what I am seeing you are not providing, a required argument which is the slug, and 'cart' is supposed to be a string. https://docs.djangoproject.com/en/1.8/ref/urlresolvers/
url = reverse('cart', args=(slug,))
return HttpResponseRedirect(url)

Related

How can I use concatenation within a request.POST.get() function? (django/python)

I was trying to iterate request.POST.get() to get some inputs from my view's corresponding html file using concatenation.
However, no matter whether the input is filled, it always says that the input returns the fallback. (As in the default response that the programmer gives.)
Does anyone know how to solve this? I'm trying to make it so it adds each choice to the set of choices for each question.
create.html
{% extends "polls/base.html" %}
{% block title %}Create a Poll{% endblock title %}
{% block header %}Create:{% endblock header %}
{% load custom_tags %}
{% block content %}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:create' %}" method="post"> {% csrf_token %}
{% for field in questionfields %}
{% if field == 'question_text' %}
<label for="{{ field }}">{{ field|capfirst|replace }}:</label>
<input type="text" name="{{ field }}" id="{{ field }}">
<br>
{% endif %}
{% endfor %}
<br>
{% for choice in choicenumber|rangeof %}
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
<br>
<br>
<input type="submit" value="Create" name="submit">
</form>
{% endblock content %}
views.py
def create(request):
choicenumber = 3
context = {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
}
submitbutton = request.POST.get('submit', False)
if submitbutton:
new_question = Question.objects.create(question_text=request.POST.get('question_text', ''), pub_date=timezone.now())
if new_question.question_text == '':
context = {
'questionfields': Question.__dict__,
'error_message': "No poll question entered.",
'choicenumber': choicenumber,
}
del new_question
return render(request, 'polls/create.html', context)
else:
new_question.save()
for i in range(choicenumber):
choice = request.POST.get(('choice' + str(i)), '')
new_question.choice_set.add(choice)
new_question.save()
return HttpResponseRedirect(reverse('polls:results', args=(new_question.id,)))
else:
return render(request, 'polls/create.html', context)
The error: TypeError at /polls/create/
'Choice' instance expected, got ''
Request Method: POST
Request URL: http://127.0.0.1:8000/polls/create/
Django Version: 3.0.8
Exception Type: TypeError
Exception Value: 'Choice' instance expected, got ''
The error was in line 52 of the file:
new_question.choice_set.add(choice)
I would be really thankful if anyone could help.
EDIT::
The models as requested:
models.py
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.boolean = True
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.short_description = 'Published recently?'
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
Then else part should be like this:
else:
new_question.save(commit=False)
for i in range(choicenumber):
choice = request.POST.get('choice' + str(i), '')
if choice:
choice_obj = Choice.objects.create(question=new_question,choice_text=choice)
new_question.choice_set.add(choice_obj)
new_question.save()
return HttpResponseRedirect(reverse('polls:results', args=(new_question.id,)))

Django - Template does not show DetailView

I am encountering the following error when trying to set DetailView for each of the post in my postlist:
NoReverseMatch at /blog/post-list/ Reverse for 'postdetail' with
keyword arguments '{'id': ''}' not found. 1 pattern(s) tried:
['blog\/post-list/(?P\d+)/$']
Here the code:
views.py
def PostList(request):
postlist = Post.objects.all()
context = {
"postlist":postlist
}
template_name = "postlist.html"
return render(request,template_name,context)
def PostDetail(request,id):
post = get_object_or_404(Post,id=id)
context = {
'post':post
}
template_name = "postdetail.html"
return render(request,template_name,context)
postlist.html
{% extends "base.html" %}
{% block content %}
<div class="container">
<div class="row">
<div class="col">
{% for item in postlist %}
<ul>
<li><h3>Title:</h3> {{ item.title }} <smal>{{ item.timestamp }}</smal></li>
<li><h3>description:</h3>{{ item.description }}</li>
<li><h3>Updated:</h3>{{ item.updated }}</li>
<li><h>Author: {{ item.Author }}</h></li>
{{ item.id }}
</ul>
{{ item }}
{% endfor %}
</div>
</div>
</div>
{% endblock %}
urls.py
urlpatterns = [
re_path(r'^post-list/$',views.PostList,name ='postlist'),
re_path(r'^post-list/(?P<id>\d+)/$',views.PostDetail,name="postdetail"),
path ('post-create',views.CreatPost, name='post-create'),
re_path (r'^post-list/update/(?P<id>\d+)/$',views.PostUpdateis,name='update-post'),
# re_path(r'^(?P<slug_post>[-\w])+/$',views.PostDetail,name="postdetail"),
]
Does anybody know how to solve this?

Restrict each user to only vote once (Polls, django, python)

I found an similar question here, but unlike there and unlike in django official tutorial , I don't have a separate Choice class. How can I restrict every user to vote just one? What should I change in my code?
my models.py:
from django.contrib.auth.models import User
class Law(models.Model):
#some code here
yes_votes = models.IntegerField(default=0)
no_votes = models.IntegerField(default=0)
class Voter(models.Model):
user = models.ForeignKey(User)
law = models.ForeignKey(Law)
my views.py:
class LawDetailView(generic.DetailView):
model = Law
template_name = 'law_detail.html'
def get_queryset(self):
"""
Excludes any petitions that aren't published yet.
"""
return Law.objects.filter(pub_date__lte=timezone.now())
class LawResultsView(generic.DetailView):
model = Law
template_name = 'law_results.html'
def law_yes_vote(request, law_id):
if Voter.objects.filter(law_id=law_id, user_id=request.user.id).exists():
return render(request, 'law_detail.html', {
'law': p,
'error_message': "Sorry, but you have already voted."
})
else:
p = get_object_or_404(Law, pk=law_id)
p.yes_votes += 1
p.save()
return HttpResponseRedirect(reverse('laws:law_results', args=(p.id,)))
def law_no_vote(request, law_id):
if Voter.objects.filter(law_id=law_id, user_id=request.user.id).exists():
return render(request, 'law_detail.html', {
'law': p,
'error_message': "Sorry, but you have already voted."
})
else:
p = get_object_or_404(Law, pk=law_id)
p.no_votes += 1
p.save()
return HttpResponseRedirect(reverse('laws:law_results', args=(p.id,)))
my law_detail.html:
{% if request.user.is_authenticated %}
{% if error_message %}
<h1 >{{ error_message }}</h1>
{% else %}
<div class="row" id="row-voting">
<form action="{% url 'laws:law_yes_vote' law.id %}" method="post">
{% csrf_token %}
<button class="btn btn-success" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" >
<label >YES</label>
</form>
<form action="{% url 'laws:law_no_vote' law.id %}" method="post">
{% csrf_token %}
<button class="btn btn-danger" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" >
<label >NO</label>
</form>
</div>
{% endif %}
{% else %}
<h1>Please, register</h1>
{% endif %}
It looks like you have forgotten to create the voter instance after the user has voted.
def law_yes_vote(request, law_id):
if Voter.objects.filter(law_id=law_id, user_id=request.user.id).exists():
return render(request, 'law_detail.html', {
'law': p,
'error_message': "Sorry, but you have already voted."
})
else:
p = get_object_or_404(Law, pk=law_id)
p.yes_votes += 1
p.save()
Voter.objects.create(law_id=law_id, user_id=request.user.id)
return HttpResponseRedirect(reverse('laws:law_results', args=(p.id,)))
You'll need to update law_no_vote in the same way.

Error checkin Python-Flask

Here is my route function :
#app.route('/home/shelter/<int:shelter_id>/', methods=['GET','POST'])
def showShelterDetails(shelter_id):
shelter = session.query(Shelter).filter_by(id = shelter_id).one()
if request.method == 'POST':
if request.form['shelterName']:
shelter.name = request.form['shelterName']
session.add(shelter)
session.commit()
flash("Shelter("+shelter.name+") edited successfully!")
return render_template('shelterdetails.html', shelter_id=shelter_id, shelter=shelter)
else:
flash(u'Error Occured!','error')
return render_template('shelterdetails.html', shelter_id=shelter_id, shelter=shelter)
if request.form['shelterAddress']:
shelter.name = request.form['shelterAddress']
session.add(shelter)
session.commit()
flash("Shelter("+shelter.name+") address edited successfully!")
return render_template('shelterdetails.html', shelter_id=shelter_id, shelter=shelter)
else:
flash(u'Error Occured!','error')
return render_template('shelterdetails.html', shelter_id=shelter_id, shelter=shelter)
else:
return render_template('shelterdetails.html', shelter_id = shelter_id, shelter = shelter)
Here is my HTML template :
{% extends "master.html" %}
{% block title %}Home{% endblock %}
{% block body %}
{% with messages = get_flashed_messages(category_filter=["message"]) %}
{% if messages %}
<div class="alert alert-success">
{% for message in messages %}
<strong>{{message}}!</strong>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% with errors = get_flashed_messages(category_filter=["error"]) %}
{% if errors %}
<div class="alert alert-danger">
{% for message in errors %}
<strong>{{message}}!</strong>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<form action="{{ url_for('showShelterDetails',shelter_id=shelter_id )}}" method = 'post'>
<fieldset class="form-group">
<label for="shelterName">Name :</label>
<input type="text" class="form-control" style="width:500px" name="shelterName" value='{{ shelter.name }}' >
</fieldset>
<fieldset class="form-group">
<label for="shelterName">Address :</label>
<input type="text" class="form-control" style="width:500px" name="shelterAddress" value='{{ shelter.address }}'>
</fieldset>
My problem is : The POST method doesn't check whether the shelterAddress field is empty or blank or not. Also while returning the success or failure messages. Only the top 1 message gets printed.
Why do the other messages not get printed ? Also why doesn't it check for empty fieds ?
EDIT 1:
Changed my view function to :
#app.route('/home/shelter/<int:shelter_id>/', methods=['GET','POST'])
def showShelterDetails(shelter_id):
shelter = session.query(Shelter).filter_by(id = shelter_id).one()
if request.method == 'POST':
if request.form['shelterName']!="":
shelter.name = request.form['shelterName']
session.add(shelter)
session.commit()
flash("Shelter("+shelter.name+") edited successfully!")
if request.form['shelterAddress']!= "":
shelter.name = request.form['shelterAddress']
session.add(shelter)
session.commit()
flash("Shelter("+shelter.name+") address edited successfully!")
else:
return render_template('shelterdetails.html', shelter_id = shelter_id, shelter = shelter)
ValueError: View function did not return a response
That's because you're returning early whether request.form['shelterName'] is truthy or not. You probably want one return statement at the very end of your view function instead.

Next and Before Links for a django paginated query

I'm trying to make a search form for Django.
Its a typical search form and then returns a table of matches. I wish to paginate the tables returned.
The problem lies in the Previous and Next buttons.
The links for the return query goes to /records/search/?query=a (search sample is a)
The page outputs the table and its previous and next links. However the links redirect to /records/search/?page=2 and the page displays a blank table.
Any help on which links I should pass for Prev/Next?
search.html:
{% extends 'blank.html' %}
{% block content %}
<div class="row">
<form id="search-form" method="get" action=".">
{{ form.as_p }}
<input type="submit" value="Search" />
</form>
</div>
<br><br>
//display table code//
{% if is_paginated %}
<div class="pagination">
<span class="step-links">
{% if agent_list.has_previous %}
forrige
{% endif %}
<span class="current">
Page {{ agent_list.number }} of {{ agent_list.paginator.num_pages }}.
</span>
{% if agent_list.has_next %}
Next
{% endif %}
</span>
</div>
{% endif %}
{% endblock %}
and the search view:
def search_page(request):
form = SearchForm()
agents = []
show_results=False
if request.GET.has_key('query'):
show_results=True
query=request.GET['query'].strip()
if query:
form=SearchForm({'query': query})
agents = \
Agent.objects.filter(Q(name__icontains=query))
paginator = Paginator(agents, 10)
page = request.GET.get('page')
try:
agents = paginator.page(page)
except PageNotAnInteger:
agents = paginator.page(1)
except EmptyPage:
agents = paginator.page(paginator.num_pages)
variables = RequestContext(request,
{ 'form': form,
'agent_list': agents,
'show_results': show_results,
'is_paginated': True,
}
)
return render_to_response('search.html', variables)
I've seen the similar questions but I can't understand/make them work. Any help?
Edit:
For a quickfix (haven't really looked at the cons)
I added a variable in my view:
variables = RequestContext(request,
{ 'form': form,
'agent_list': agents,
'show_results': show_results,
'is_paginated': True,
**'query': query,**
}
)
Where query without the quotes is the recieved query variable.
Then simply change the URL to:
Previous
If you have a better way of answering the question, please do or appending a URL to your currently opened URL.
I would recommend putting the solution in a template tag like so:
myapp/templatetags/mytemplatetags.py:
from django import template
register = template.Library()
#register.simple_tag
def url_replace(request, field, value):
d = request.GET.copy()
d[field] = value
return d.urlencode()
#register.simple_tag
def url_delete(request, field):
d = request.GET.copy()
del d[field]
return d.urlencode()
Then from templates do:
{% load mytemplatetags %}
...
previous
you can use {{ request.get_full_path }} this tag to get current url.
Next
this worked for me
The below works before and after a search form has been submitted:
Views.py
class PostListView(ListView):
model = Post #.objects.select_related().all()
template_name = 'erf24/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts' # default >> erf24/post_list.html
ordering = ['date_posted']
paginate_by = 3
def is_valid_queryparam(param):
return param != '' and param is not None
def invalid_queryparam(param):
return param == '' and param is None
class SearchView(ListView):
model = Post #.objects.select_related().all()
template_name = 'erf24/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts' # default >> erf24/post_list.html
ordering = ['date_posted']
paginate_by = 3
def get_queryset(self): # new
key = self.request.GET.get('key')
minp = self.request.GET.get('min')
maxp = self.request.GET.get('max')
if is_valid_queryparam(key):
obj = Post.objects.filter(Q(content__icontains=key) | Q(location__icontains=key)).distinct().order_by('date_posted')
if is_valid_queryparam(minp):
obj = Post.objects.filter(Q(price__gte=minp)).distinct().order_by('date_posted')
if is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(price__lte=maxp)).distinct().order_by('date_posted')
if is_valid_queryparam(minp) & is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(price__gte=minp) & Q(price__lte=maxp)).distinct().order_by('date_posted')
if is_valid_queryparam(key) & is_valid_queryparam(minp) & is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(content__icontains=key) | Q(location__icontains=key)).distinct()
obj = obj.filter(Q(price__gte=minp) & Q(price__lte=maxp)).order_by('date_posted')
if invalid_queryparam(key) & invalid_queryparam(minp) & invalid_queryparam(maxp):
obj = Post.objects.all()
return obj
url.py
urlpatterns = [
path('', PostListView.as_view(), name='erf24-home'),
path('search/', SearchView.as_view(), name='erf24-search'),
]
Home.html
<form action="{% url 'erf24-search' %}" method="GET">
<div class="form-group">
<label for="inputAddress">Search keyword</label>
<input type="text" class="form-control" id="key" name="key" placeholder="keyword">
</div>
<label for="">Price</label>
<div class="form-row">
<div class="form-group col-md-6">
<input type="number" class="form-control" id="min" name="min" placeholder="min price">
</div>
<div class="form-group col-md-6">
<input type="number" class="form-control" id="max" name="max" placeholder="max price">
</div>
</div>
<button type="submit" class="btn btn-primary btn-sm mt-1 mb-1">Search</button>
<button type="reset" class="btn btn-secondary btn-sm mt-1 mb-1">Clear</button>
</form>
{% for post in posts %}
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}" alt="">
{{ post.author }}
<small class="text-muted">{{ post.date_posted }}</small>
<!-- use |date: "specs" to filter date display -->
</div>
<h2>
{{ post.price }}
</h2>
<p class="article-content">{{ post.content }}</p>
<p class="article-content">{{ post.location }}</p>
<p><a class="like-btn" data-href="{{ post.get_api_like_url }}" href="">{{ post.likes.count }}
{% if user in post.likes.all %} Unlike
{% else %} Like
{% endif %}
</a></p>
</div>
{% for image in post.image_set.all %}
<img class="account-img" src="{{ image.image.url }}" alt="">
{% endfor %}
</article>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
First
Previous
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
{{ num }}
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
{{ num }}
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
Next
Last
{% endif %}
{% endif %}
Worked like a charm :) Enjoy!
You can use {{ request.get_full_path }} template tag
Next
you can use this, I use it because I use filters in the url itself, so all the url params are used to build the next or previous url
import re
from django import template
register = template.Library()
PAGE_NUMBER_REGEX = re.compile(r'(page=[0-9]*[\&]*)')
#register.simple_tag
def append_page_param(value,pageNumber=None):
'''
remove the param "page" using regex and add the one in the pageNumber if there is one
'''
value = re.sub(PAGE_NUMBER_REGEX,'',value)
if pageNumber:
if not '?' in value:
value += f'?page={pageNumber}'
elif value[-1] != '&':
value += f'&page={pageNumber}'
else:
value += f'page={pageNumber}'
return value
then, in your pagination nav you can call it like this:
{% append_page_param request.get_full_path page_obj.previous_page_number %}

Categories