django - python: failed using reverse : no reverse match - python

I have the following Views:
def default_new (request):
if request.method == "POST":
post = EquipmentForm(request.POST)
if form.is_valid():
post.save()
return HttpResponseRedirect(reverse('calbase:default_detail', args=(id,)))
else:
form = EquipmentForm()
return render(request, 'calbase/default_edit.html', {'form':form})
class default_detail (generic.DetailView):
model = Equipment
template_name = 'calbase/default_detail.html'
And urls:
urlpatterns = [
url(r'^$', views.default, name = 'default'),
url(r'^default/((?P<id>\d+)/$)', views.default_detail.as_view(), name = 'default_detail'),
url(r'^default/new/$', views.default_new, name = 'default_new'),
]
What I would like to do here is just to take in a form input, save it, and then redirect to its detail view. However, although the form is correctly saved, it always give me errors like:
NoReverseMatch at /calbase/default/new/
Reverse for 'default_detail' with arguments '(<built-in function id>,)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['calbase/default/((?P<id>\\d+)/$)']
Could somebody help me figuring out what's wrong here pls?

The problem is you are using id, which is a built in function.
When you call form.save(), it will return the Post instance. Use post.id (or post.pk if you prefer) to get the id of the post.
def default_new(request):
if request.method == "POST":
form = EquipmentForm(request.POST)
if form.is_valid():
post = form.save()
return HttpResponseRedirect(reverse('calbase:default_detail', args=(post.id,)))
You also have too many parentheses in your url pattern. It should be:
url(r'^default/(?P<id>\d+)/$', views.default_detail.as_view(), name = 'default_detail'),

Related

How do I redirect to url2 after performing a task on url1 in django?

I have a edit-scholarship.html in which you can search for a scholarship by passing name and type and then select that scholarship and edit it in update-scholarship.html by passing scholarship id from the url.
Now after updating the scholarship, the url becomes
http://127.0.0.1:8000/admin/updatescholarship/50
50 is the scholarship id passed into the url
Now when I try to go to dashboard in my project, the url becomes
http://127.0.0.1:8000/admin/updatescholarship/dashboard
I dont't want the dashboard to get appended after the updatescholarship . The url should be
http://127.0.0.1:8000/admin/dashboard
Here's my edit-scholarship view
def admin_editscholarship(request):
if request.method == 'POST':
name = request.POST['sch_name']
type = request.POST['sch_type']
schdets = ScholarshipDetails.objects.filter(name = name,type = type)
if schdets is not None:
#if something exists in scholarship details, then print it
print('Scholarship found')
else:
schdets = None
return render(request,'admin-editscholarship.html',{'schdets':schdets})
Here's my update-scholarship view
def admin_updatescholarship(request,pk=None):
#can update the new data in the selectd scholarship
if pk:
sch = ScholarshipDetails.objects.get(pk = pk)
if request.method == 'POST':
form = EditScholarshipForm(request.POST,instance=sch)
if form.is_valid():
form.save()
print('\nform saved')
args = {'form' : form}
messages.success(request,'Successfully updated')
return render(request,'admin-editscholarship.html',args)
Here's my urls.py
path('admin/dashboard',views.admin_dash),
path('admin/addscholarship',views.admin_addscholarship),
path('admin/editscholarship',views.admin_editscholarship),
url(r'^admin/updatescholarship/(?P<pk>\d+)$',views.admin_updatescholarship,name =
'updatescholarship'),
path('admin/students',views.admin_students),
path('admin/requests',views.admin_requests)
you can redirect to other url using django redirect
from django.shortcuts import redirect
def fn_test(request):
task here
return redirect('path_to_redirect/')

Django-2.2 NoReverseMatch error. Cannot redirect to next page

After submission of a create form in my web app it should redirect in to a single page where it displays the new product that is entered. instead of that, it shows :
Reverse for 'category' with keyword arguments '{'pk': UUID('e3ec4273-22c9-450f-87c9-d12973dce3c1')}' not found. 1 pattern(s) tried: ['app/products/category/<int:pk>']
views.py
def create_category(request):
if request.method=='POST':
form = CategoryForm(request.POST,request.FILES)
if form.is_valid():
data = form.save(commit=False)
data.creator = request.user
data.updater = request.user
data.auto_id = get_auto_id(ProductCategory)
data.save()
return HttpResponseRedirect(reverse('products:category',kwargs={"pk":data.pk}))
else:
...
else:
...
def category(request,pk):
instance = get_object_or_404(ProductCategory.objects.filter(pk=pk))
context = {
'title': "Category : " + instance.name,
'instance' : instance,
}
return render(request,'products/category.html',context)
urls.py
from django.urls import path
from . import views
app_name = 'products'
urlpatterns = [
path('categories',views.categories,name='categories'),
path('category/create',views.create_category,name='create_category'),
path('category/<int:pk>',views.category,name='category'),
path('category/edit/<int:pk>',views.edit_category,name='edit_category'),
path('category/delete/<int:pk>',views.delete_category,name='delete_category'),
]
Th thing is the form is submitted and the values are added to database. But it doesn't move to the next step.
I am new to django 2 so not very sure on how to pass pk in urls/path
In your url:
path('category/<int:pk>',views.category,name='category'),
^^^^
You are expecting an integer but in code you are passing an UUID. So change the url to:
path('category/<uuid:pk>',views.category,name='category'),
More information can be found in documentation.

Django2: After form submission is there a better way to 'wipe' the POST to stop re-submission

I have a django application and on one page I have several forms for different models. I would like a 'success' message, which is easy to do by just adding to the context after form submission/validation. However, this leaves the possibility of re-submission of the form, which would just produce an error back to the page, but it still annoys me.
urls:
url_patterns = [
re_path(r'^manager/$', Manager.as_view(), name='manager'),
.......more.....
]
views.py:
class Manager(LoginRequiredMixin, View):
template_name = 'results/manager_templates/manager.html'
form1 = Form1
form2 = Form2
login_url = '/'
redirect_field_name = 'redirect_to'
def get(self, request, *args, **kwargs):
form1 = self.form1()
form2 = self.form2()
context = {
'form1': form1,
'form2': form,}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
submit_clicked = request.POST.get('submit')
form1 = self.form1()
form2 = self.form2()
context = {}
if submit_clicked == 'Form 1':
form1 = self.form1(request.POST)
if form1.is_valid():
form1.save()
context['message'] = 'Form 1 successful'
# reset the form
form1 = self.form1()
# return HttpResponseRedirect(
# reverse('results:manager',
# ))
else:
print('NOT VALID')
elif submit_clicked == 'Form 2':
... do same stuff as above ...
context['form1'] = form1
context['form2'] = form2
return render(request, self.template_name, context)
If I were to uncomment out the HttpResponseRedirect out, after the form was validated and added like so:
return HttpResponseRedirect(
reverse('results:manager',
))
Then it returns me to my page, and if i refresh the form isnt re-submitted. However I can't pass this an argument without it going through the url:
i.e if I were to write:
return HttpResponseRedirect(
reverse('results:manager',
kwargs={'success':'success'}
))
I get the error:
Reverse for 'manager' with keyword arguments '{'success': 'success'}' not found. 1 pattern(s) tried: ['manager/$']
and if I change urls.py to:
url_patterns = [
re_path(r'^manager/$', Manager.as_view(), name='manager'),
re_path(r'^manager/(?P<success>)$', Manager.as_view(), name='manager'),
]
I get the error:
Reverse for 'manager' with keyword arguments '{'success': 'success'}' not found. 2 pattern(s) tried: ['manager/(?P<success>)$', 'manager/$']
Is there anyway to pass HttpResponseRedirect variables that dont need to be added to url regex? Or is there any other way to 'reset' my request.POST so that forms dont get re-submitted, without using HttpResponseRedirect?
As you've found, you should redirect after a successful post to prevent duplicate requests.
When you changed the urls, you didn't add any characters to match in your success group.
re_path(r'^manager/(?P<success>\w+)$', Manager.as_view(), name='manager'),
Another option is to store the variable in the querystring, e.g. /manager/?success=success, then you can retrieve the value from request.GET after the redirect.
You could also store data in the session, or use the messages framework.

invalid django form makes is_valid method always return false

My django form is invalid and so the .is_valid method never returns true. As a result, I am getting an "Expected HttpResponse but received None" type of error because my code never executes what is within the if-condition. I am wondering how to make my form valid. I am new to django so I am probably missing something obvious. Here is my code:
views.py
template_name1 = 'multiplication/detail.html'
template_name2 = 'multiplication/multiplied.html'
class myForm(forms.Form):
quantity1 = forms.IntegerField(required=False)
quantity2 = forms.IntegerField(required=False)
form = myForm()
def get(request):
return render(request,template_name1,{'form': form} )
def multiply_two_integers(x,y):
return x*y
def post(request):
if (form.is_valid()):
x = request.POST.get('quantity1')
y = request.POST.get('quantity2')
product = multiply_two_integers(x, y)
return render(request, template_name2, {'form': form, 'product':
product })
template_name1
<h1>Multiplication Function</h1>
<form action = "{% url 'multiplication:post' %}" method = "post">
{{ form.as_p }}
{% csrf_token %}
<input type = "submit" value ="Multiply">
<!--<button type="submit"> Multiply </button>-->
<h1>{{product}}</h1>
</form>
template_name2
<h1>{{product}}</h1>
urls/multiplication
from django.urls import path
from multiplication import views
app_name = 'multiplication'
urlpatterns = [
# /multiplication/
path('', views.get, name = 'get'),
path('multiplied', views.post, name='post')
]
This code is very strange. You seem to have a set of functional views, but are trying to randomly use some concepts from class-based views.
The reason why your form is not valid is because you never pass any data to it; an unbound form cannot be valid. You should not be instantiating the form outside of a view; you need to do it in the view, and when the request is a POST you should pass the POST data to it.
In function-based views you should not define separate functions for get and post. Combine them, as sown in the Django docs.
There is another point that you have missed about the error message; your reaction to it telling you that you have not returned a response if the form is invalid is to ask "why isn't it valid", but you should also do what it says and return a response in this case; the form will sometimes be actually invalid, and you should deal with this case.
Finally, to get the data from the form you should use form.cleaned_data, not request.POST.
def multiply_two_integers(x,y):
return x*y
def my_view(request):
if request.method == 'POST':
form = MyForm(request.POST)
if (form.is_valid()):
x = form.cleaned_data['quantity1']
y = form.cleaned_data['quantity2']
product = multiply_two_integers(x, y)
return render(request, template_name2, {'product': product })
else:
form = MyForm()
return render(request,template_name1,{'form': form} )

An NoReverseMatch Error

I know that NoReverseMatch problem means something wrong with my URLs, but I just could not find where the problem is
views.py:
def edit(request,post_id):
e = Note.objects.get(id=post_id)
form = Edit()
if request.method == 'POST':
form = Edit(request.POST.copy())
if form.is_valid():
data1 = form.cleaned_data
g = Note.objects.get(id=post_id)
g.title = data1['title']
g.content = data1['content']
g.category = data1['category']
g.subject_name = data1['subject_name']
g.save()
return HttpResponseRedirect('/notebook/')
else:
return HttpResponse('Not good')
else:
form = Edit(initial={'title': e.title,'content': e.content, 'category' : e.category,
'subject_name': e.subject_name})
return render(request,'notebook/edit.html',{'form': form})
in urls.py:
urlpatterns = [
url(r'^$', views.homepage, name='homepage'),
url(r'^(?P<post_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^(?P<post_id>[0-9]+)/delete/$', views.delete, name='delete'),
url(r'^edit/(?P<post_id>[0-9]+)/$', views.edit, name='edit'),
url(r'^/post/$', views.post, name='post'),
url(r'^category(?P<category>\w+)/$', views.show_category, name='show_category'),
url(r'^subject(?P<id>\w+)/$', views.show_subject, name='show_subject'),
url(r'^/create_subject/$', views.create_subject, name='create_subject'),
# url(r'/upload_image/$', views.upload_image, name='upload_image'),
]
The Error:
Reverse for 'edit' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['notebook/edit/(?P<post_id>[0-9]+)/$']
And by the way, I have to say this, which I think is important, before I added the class Subject, which means the form had nothing to do with it in the first place, the function edit() worked just fine.
And besides, parts of my form looks like this:
class Edit(forms.Form):
title = forms.CharField(label=('title')
content = forms.CharField(label=('content'),widget=forms.Textarea)
category = forms.CharField(label=('category')
subject_name = forms.ModelChoiceField(queryset=Subject.objects.all())
You are most likely using a url filter tag in your template. You need to pass the post_id as a parameter in your url filter tag.
{% url 'edit' post_id %}
On a side note, you should preferably use reverse or reverse_lazy to get url's rather than hard coding them
from django.core.urlresolvers import reverse_lazy, reverse
HttpResponseRedirect(reverse('url_name'))

Categories

Resources