Form Confirmation - python

I'm trying to pass data from a successful form submission to a thank you page that could then display this data. I am trying to do a reverse HttpResponseRedirect, but I keep getting this error:
NoReverseMatch at /contactform/process
Reverse for 'thankyou' with arguments '(24,)' not found. 1 pattern(s) tried: [u'contactform/thankyou/$']
Here is the code I have so far:
views.py
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from .models import Contact_Object
def index(request):
template_name = 'contactform/index.html'
return render(request, 'contactform/index.html')
def thankyou(request, entered_id):
contact_info = get_object_or_404(Contact_Object, pk=contact_object_id)
template_name = 'contactform/thankyou.html'
return render(request, 'contactform/thankyou.html', {name: contact_info.name})
def process(request):
entered_name = request.POST['fullname']
entered_email = request.POST['email']
entered_message = request.POST['message']
entered = Contact_Object(name=entered_name, email=entered_email, message=entered_message)
entered.save()
entered_id = entered.id
return HttpResponseRedirect(reverse('contactform:thankyou', args=(entered.id,)))
urls.py
from django.conf.urls import url
from . import views
app_name = 'contactform'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^thankyou/$', views.thankyou, name='thankyou'),
url(r'^process$', views.process, name='process'),
]
Template for Form
<H1>Contact Form</H1>
<FORM action="{% url 'contactform:process' %}" method="post">
{% csrf_token %}
Full Name:<br>
<input type="text" name="fullname"><br>
Email:<br>
<input type="text" name="email" ><br>
Message:<br>
<textarea name="message" cols="40" rows="5"></textarea>
<input type="submit" value="Enter">
</FORM>
Template for Thank you page
<h1>Thank You</h1>
<p>Thank you, {% contact_info.name %}</p>
I'm new to working with Python/Django so I feel it's probably an obvious beginners mistake, I just can't seem to spot it.
Thanks in advance.

Your problem is right here:
return HttpResponseRedirect(reverse('contactform:thankyou', args=(entered.id,)))
the thankyou url doesn't take any arguments.
url(r'^thankyou/$', views.thankyou, name='thankyou'),
To fix it you should change it to this:
url(r'^thankyou/([0-9]*)$', views.thankyou, name='thankyou'),
Using the reverse function and the args kwarg, it translates it into a usable URL like: /thankyou/24 plugging in the args provided in the args iterable. You can also use kwargs to pass in keywords to your url if you're using keyword groupings in your url as described below.
See here: https://docs.djangoproject.com/en/1.11/topics/http/urls/#example
Each of the regex groupings is an argument that gets passed to the view.
You can also have keyword arguments passed if you do the url like this:
url(r'^thankyou/(?P<pk>[0-9]*)$', views.thankyou, name='thankyou'),
and in a function based view you would access it by defining it in the view function signature like this:
def thankyou(request, pk=None):

Related

django: unable to redirect to another view in django

I'm trying to click on a button in http://127.0.0.1:8000/main/electronics/switch/ to call getCommodityCommentDetail to do something, and then redirect to another page commodityInfoPage.
What puzzles me is that the page always shows the same content in the initial page, although the url has changed e.g. to http://127.0.0.1:8000/main/comments/1/.
After testing, I found that the commodityInfoPage in views.py isn't called. I have searched long time for solutions, but all of them failed. So how can I fix it?
urls.py:
app_name = 'main'
urlpatterns = [
# eg:127.0.0.1:8000/main/
path('', views.index, name = 'index'),
path('getCommodityInfo/', views.getCommodityInfo, name = 'getCommodityInfo'),
path('getCommodityCommentDetail/', views.getCommodityCommentDetail, name="getCommodityCommentDetail"),
path('<str:category>/<str:searchKey>/',views.commodityInfoPage, name = 'commodityInfoPage'),
path('comments/<str:commodityId>/', views.commodityCommentPage,name = 'commodityCommentPage'),
]
view.py:
def getCommodityCommentDetail(request):
if request.method=="POST":
commodityId = request.POST.get("commodityId")
# scrapy module is waiting implementation
#
return HttpResponseRedirect(reverse('main:commodityInfoPage',args=(commodityId)))
def commodityCommentPage(request, commodityId):
print("enter commodityCommentPage")
commentList = JDCommentDetail.objects.all()
context = {'commentList':commentList}
return render(request,'main/commodityCommentPage.html',context)
templates:
<form action="{% url 'main:getCommodityCommentDetail'%}" method="POST">
{% csrf_token %}
<input class="hidden" value="{{commodity.id}}" name="commodityId">
<button type="submit" class="btn btn-default" >review</button>
</form>
The problem is that comments/1/ is matched by the commodityInfoPage URL pattern.
path('<str:category>/<str:searchKey>/',views.commodityInfoPage, name='commodityInfoPage'),
You can fix this problem by changing the URL patterns so that they don't clash, or by moving the commodityCommentPage URL pattern above the commodityInfoPage one.
path('comments/<str:commodityId>/', views.commodityCommentPage, name='commodityCommentPage'),
path('<str:category>/<str:searchKey>/', views.commodityInfoPage, name='commodityInfoPage'),
Note that if you re-order the patterns, you won't be able to view commodityInfoPage if the category is 'comments'.

NoReverseMatch at / django 1.8 form

Im getting this error trying to load my index.html that has a form inside with a view call on the "action" tag.
NoReverseMatch at /
Reverse for 'create' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Request Method: GET
Request URL: http://localhost:8000/
Django Version: 1.8.3
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'create' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
This is my urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^create_project/$', views.create, name='create'),
]
This is my view.py:
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
def index(request):
return render(request, 'menu/index.html')
def create(request):
return render(request, 'menu/detail.html')
This is the index.html part that shows the action tag that raises the error:
<form class="nobottommargin" id="template-contactform" name="template-contactform" action="{% url 'create' %}" method="post">
{% csrf_token %}
<div class="col_half">
<label for="name">Project Name <small>*</small></label>
<input type="text" id="name" name="name" value="{{ current_name }}" class="sm-form-control required" />
</div>
I dont know what im doing wrong, hope you can help me!
I made a test with your data in the same Django version and work, check either because it must be something that is not there and has not imported.
The mistake was tha my urls have been included by another urls.py.
Thanks #Daniel Roseman

Very simple user input in django

My underlying struggle is I am having trouble understanding how django templates, views, and urls are tied together... What is the simplest, bare minimum way to prompt the user to input a string, then use that string to query a database (preferably w/ python model not raw sql queries)? Should I use GET and POST methods? Should I use a form? Do I need to use a template or can I use a generic view?
when i try submitting input it just reloads the input page.
views.py:
from django.shortcuts import render
from django.shortcuts import HttpResponse
from People.models import Person
def index(request):
return render(request, 'People/index.html')
def search(request):
search_id = request.POST.get('textfield', None)
try:
user = Person.objects.get(MAIN_AUTHOR = search_id)
#do something with user
html = ("<H1>%s</H1>", user)
return HttpResponse(html)
except Person.DoesNotExist:
return HttpResponse("no such user")
urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^People/', 'People.views.index'),
url(r'^People/send/', 'People.views.search'),
)
template:
<form method="POST" action="send/">
{% csrf_token %}
<input type="text" name="textfield">
<button type="submit">Upload text</button>
</form>
Am I missing something or doing something wrong?
If I understand correctly, you want to take some input from the user, query the database and show the user results based on the input. For this you can create a simple django form that will take the input. Then you can pass the parameter to a view in GET request and query the database for the keyword.
EDIT:
I have edited the code. It should work now.
views.py
from django.shortcuts import render
from django.shortcuts import HttpResponse
from .models import Person
from django.core.exceptions import *
def index(request):
return render(request, 'form.html')
def search(request):
if request.method == 'POST':
search_id = request.POST.get('textfield', None)
try:
user = Person.objects.get(name = search_id)
#do something with user
html = ("<H1>%s</H1>", user)
return HttpResponse(html)
except Person.DoesNotExist:
return HttpResponse("no such user")
else:
return render(request, 'form.html')
urls.py
from django.conf.urls import patterns, include, url
from People.views import *
urlpatterns = patterns('',
url(r'^search/', search),
url(r'^index/', index)
)
form.html
<form method="POST" action="/search">
{% csrf_token %}
<input type="text" name="textfield">
<button type="submit">Upload text</button>
</form>
Also make sure that you place your templates in a seperate folder named templates and add this in your settings.py:
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), '../templates').replace('\\','/'),
)
For a user input you'll need 2 views - one to display the page with the form and another to process the data. You hook the first view to one url, say "feedback/", and the other one to a url like "feedback/send/". You also need to specify this second url in your form tag.
<form method="POST" action="feedback/send/">
<input type="text" name="textfield">
...
<button type="submit">Upload text</button>
</form>
Now in the second view you can obtain the form data and do whatever you want with it.
def second_view(request):
if request.method == "POST":
get_text = request.POST["textfield"]
# Do whatever you want with the data
Take a look at this page Fun with Forms. It'll give you the basic understanding. I would also advice to work through the whole book.
You should use ether GET or POST (GET is probably not secure). Using form is not mandatory, as you can style it and perform all the validation yourself and then pass the data straight to the model.

Is there a type discrepancy that is causing this 'NoReverseMatch' in Django?

According to the Django docs, a NoReverseMatch happens when "a matching URL in your URLconf cannot be identified based on the parameters supplied."
I am getting the following NoReverseMatch error. My question is: why is the parameter supplied not being caught by the url? Is it expecting a parameter of a different type? I'm still not too comfortable with Django urls.
"Reverse for 'recall' with arguments '(<Unordered_Group: countries>,)' and keyword arguments '{}' not found. 0 pattern(s) tried: []"
This question is revised from Django NoReverseMatch url issue after suggestions were tried.
edited:
images/urls.py (project level)
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^images/', include('images_app.urls', namespace="images_app")),
url(r'^associate/', include('associate.urls', namespace="associate")),
url(r'^admin/', include(admin.site.urls)),
)
associate/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^learn/', "associate.views.learn", name='learn'),
url(r'^recall/(?P<ordered_group>\w+)', 'associate.views.recall', name='recall'),
url(r'^$', "associate.views.index", name='index'),
)
learn.html
<form action="{% url 'associate:recall' ordered_group %}" method="post"> ERROR CAUGHT
{% csrf_token %}
<div>
<label for="recall">enter as many members of {{ ordered_group }} as you can recall </label>
<input type="text" id="recall" name="recall">
</div>
<div id="enter_button">
<input type="submit" value="enter" name="enter" />
</div>
<div id="done_button">
<input type="submit" value="done" name="done" />
</div>
</form>
views.py
def recall(request, ordered_group):
...
def learn(request):
...
ordered_group = ordered_groups[index]
return render(request, 'associate/learn.html', {'dataset':model, 'ordered_group':ordered_group})
The issue is, your URL pattern is expecting a regex which matches [\w]+ which is one or more wordcharacters.
recall/(?P<ordered_group>\w+)
But it actually got an object.
A better way of doing this would be to send the id of the ordered group object (or any other unique identifier), and querying for that object in the view again.
Note that if you go with the id, URL pattern regex would be
recall/(?P<ordered_group>\d+)
and the view:
def recall(request, ordered_group):
obj = get_object_or_404(Unordered_Group, id=ordered_group)
#rest of the code..

Form - action attribute

I want to create an "index.html" Django template, which contains a button. When the button is pressed, I want to render the template "home.html", which itself displays the value "123". (Of course, there is a simpler way to do this specific task - but I am learning Django and so want to try it this way.)
Here is my views.py file:
from django.shortcuts import render
def home(request, x)
context = {'x': x}
return render(request, 'home.html', context)
Here is my urls.py file:
from django.conf.urls import patterns, include, url
from myapp import views
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^home', views.home, name='home'),
)
Here is my home.html file:
<html>
<body>
The value is: {{ x }}
</body>
</html>
Finally, here is my index.html file:
<html>
<form method="post" action=???>
<input type="button" value="Click Me">
</form>
Please can somebody tell me what I need to write in place of the ???, in the action attribute above? I have tried setting ??? = "{% url 'home' 123 %}" but this gives me a "NoReverseMatch" error. Therefore, I suspect there may be also be something wrong with my urls.py file...
Thank you!
Rewrite your index.html like this
<html>
<form method="post" action=/home>
<input type="hidden" name="my_value" value="123">
<input type="button" value="Click Me">
</form>
It contains a hidden variable called my_value its hold your value 123. And i your view.py accept this value like this,
from django.shortcuts import render
def home(request)
x = ' '
if request.POST:
x = request.POST['my_value']
context = {'x': x}
return render(request, 'home.html', context)
You get the NoReverseMatch error because you do not have a url that captures the 123 that you send along with the url. Let me tell you an easy way:
You can set the action as something like:
action="/home/123" # or any integer you wish to send.
And match that url in urls py by modifying the home url as:
url(r'^home/(?P<x>\d+)/$', views.home, name='home')
This passes whatever parameter you send in the home url(which should be an integer in this case) as x. Thus the x will be displayed in the home.html

Categories