Let's say I have the following pointless example view:
def foo(request, input):
return HttpResponse()
and in a template I have a form:
<form method="get" action="{% url 'foo' ??? %}">
<input id="myinput" type="text" name="myinput">
...
</form>
Finally, I have the following url in my URLconf:
urlpatterns = [
url(r'^foo/(.+)/', views.foo, name='foo'),
]
What I would like to do, is pass the value entered by the user into the input with the id of #myinput to the foo() view function. To put it another way, you should be able to enter bar in the html input, and when you submit the form it will take you to foo/bar/.
I know that within the foo view I could access the value of the input easily with request.GET['myinput'], but I want it to show up in the url as well.
This seems like it should be a fairly common task, but I have not been able to come up with a solution yet. Any suggestions would be appreciated. My Frankenstein's Monster of a first Django site is almost complete, and this is one of last pieces I am missing.
The source of my misunderstanding
Although I did not make this clear in an attempt to simplify my example and avoid using app-specific code, my use case is a simple search view. The view was actually one of the first views I wrote in the start of my Django journey, and I mistakenly was POSTing my data instead of GETing it. This was making it so that if I was searching for the item foo, it would take me to the detail page for foo, but the url would be mysite/search/ (i.e., the search query is not included in the url though it is included in the request), and I can't return to those search results by visiting the url mysite/search/.
While I was using a GET request in my toy example in this question, I didn't realize that I had been using a POST in my app, and that with some minor tweaking I can get the functionality I want for free very easily. I know that all of this is extremely obvious to veteran and even intermediate web developers, but for someone starting from scratch without web or cs experience, things like HTTP can be a little confusing. At least for me it is. Thanks so much to #Two-Bit Alchemist for explaining this in a way that I can understand.
Applying all this to my toy example
I would get rid of the passed parameter in my view:
def foo(request):
# If I want to do something with the search query, I can access it with
# request.GET['search_query']
return HttpResponse()
change my form in my template to:
<form method="get" action="{% url 'foo' %}">
<input id="myinput" type="text" name="search_query">
...
</form>
and change my url to:
urlpatterns = [
url(r'^foo/search/', views.foo, name='foo'),
]
As #Two-Bit Alchemist said: "The rest will happen like magic". If a user enters bar in the input and submits the form, they will be taken to foo/search/?search_query=bar. This is what I was looking for.
Related
I'm a begginer grasping at straws with difficulty dealing with the django slug url system and these NoReverseMatch errors that make no sense to me even after reading the docs.
I have a django project. In one of the views, I pass a list of geoJSON features into a template, and show them on a map. I want to have each feature act as a clickable 'link' to a view that will show stuff about it. The following is part of the template that has those features that I want to click on:
//part of the template:
<script type="text/javascript">
...
function onEachFeature(feature, layer) {
layer.on('click', function (e) {
window.location.href = "{% url 'polls:areadetail' feature.properties.myslug%}";
});
}
(I have confirmed that feature.properties.myslug does in fact contain the slug I want).
The url pattern I want to go to:
urlpatterns = [...
url(r'^areadetail/(?P<areaslug>[-\w]+)/$', views.AreaDetail, name='areadetail'),]
And the view it relates to:
def AreaDetail(request, areaslug):
area = get_object_or_404(Area, nameslug=areaslug)
return render(request, 'polls/areadetail.html', {'area':area})
The issue I get is, by doing what I show and placing that url reference inside that template I show above, that I want to be able click on, that template won't even work at all, giving me a 'Error during template rendering' full page error info that starts with:
NoReverseMatch at /polls/areas/
Reverse for 'areadetail' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'polls/areadetail/(?P[-\w]+)/$']
Any help would be immensely appreciated
EDIT part1: As I've said in response to falsetru, I'm sure feature.properties.myslug has in fact got a slug expression in it.
EDIT2: Based on something I found in a django ticket, I've made a slight change in the url regex at urls.py, from (?P<areaslug>[-\w]+)/$ to (?P<areaslug>[-\w]+)?/$ and now the error is:
Page not found (404)
Request Method: GET Request URL: http://127.0.0.1:8000/polls/areadetail// Raised by: polls.views.AreaDetail
Is it possible that because the "{% url 'polls:areadetail' feature.properties.myslug%}" bit is inside javascript, that feature.properties.myslug is not being inserted there correctly? Like some sort of brackets are needed here?
According to the error message, feature.properties.myslug is empty or has no value.
Make sure the feature.properties.myslug is passed correctly from view.
Comment out {% url .. %} temporarily.
Print {{ feature }}, {{ feature.properties }}, {{ feature.properties.myslug }} to see if which part is missing.
Fix view accordingly.
Uncomment {% url .. %}.
After some more digging around I've found the answer to why doesn't this work in another question at:
How to pass javascript variable to django custom filter
The answer to it by Ludwik Trammer says:
Django templates are build on the server side, while JavaScript is executed on the client side.
That means that template code is always executed before JavaScript (as
it is executed by the server, before the page is sent to the client).
As a consequence it is absolutely impossible to mix JavaScript and
Django code the way you want to.
Which clearly applies here. I was focused on problems with the URL template, regex on the urls.py file etc. when the problem was that no matter what I did, because it's in a javascript section, run client-side, that URL template will always be incomplete no matter what I do, therefore being an impossible solution to what I want.
I'm having a tough time figuring out how to parse my URL GET data and send it to the right view.
I have a search view that only has a search input:
template/search.html
<form action="http://domain.com/schools/search/" method="GET" >
<input type="text" name = "q_word">
<input type="submit" value="Search"/>
</form>
When a user enters in a search term, I want to send that data to another view to parse and use in a geocoding function I wrote. Here is a look at my urls.py:
url(r'^schools/search/$', school_views.find_school, name="find_school"),
url(r'^schools/search/(?P<address>[\w ]+)$', school_views.geo_locate, name="geo_locate"),
I want to grab the GET data from a URL (after they've entered in the info), and pass it as an address argument to my school_views.geo_locate function.
This set up works great when you manually type out a URL like: schools/search/150%20main%20Street
But when a user submits any form data, the URL passed is /schools/search/?q_word=150+west+main and I'm just kicked back to my search template.
I think my regex needs to be tweaked in my second url argument, but I just keep returning to the search page after submission, with no data going to my geo_locate view. Is this a URLs problem?
GET data is not passed in the URL parameters. Don't try to capture it in the regex. Just get it from request.GET inside the view.
My form submits as follows
<form class="form-signin" role="form" action="{% provider_login_url "facebook" method="js_sdk" next="/next"%}">
I overrode the DefaultAccountAdapter with my own AccountAdapter with method
def get_login_redirect_url(self, request):
print request.GET['next']
...
But request loses the next parameter and the print returns an error because there is no "next" in request.GET.
Why can't I access the next parameter?
I was originally using get_login_redirect_url to handle different url redirects after creation of social versus username/password users. Now, I need to be able to specific the next parameter in the URL for another variant of behavior for social user login but am unable to access the next parameter because it does not seem to be passed.
I am not sure whether I could give the precise solution for your issue. But I think got the point.
To access the next parameter from url,
The url should be,
http://127.0.0.1:8000/index?next=2
If you have to form the url in this above manner,you can get access to the next argument from request object in your corresponding view method
print request.GET.get('next')
So, please make sure to format request url with proper querystring refer
To your case,
I have no idea about {% provider_login_url %} template tag
I am assuming after your tag rendered it yields the url index, then i am appending my querystring next
<form class="form-signin" role="form" action="/index?next=someValue">
you may try additionally,
{% provider_login_url "facebook" next=next %}
source
I came across with a similar problem. However, I wasn't signing in with facebook. request.GET was always empty.
I think you could try using jQuery to manually append next parameter to the action attribute of <form>. See this question. It solves my problem.
i have a form in a template, but it can't reach the correspondant view. the method is GET. i've tried also to pass it an argument just to populate the query string, but the request doesnt reach the mapped view. here'sthe views.py, urls.py and the template:
template.html
<div id="search-new-btn">
<form action="/anagrafica/new/" method="get">
<input type="submit" title="Crea nuovo soggetto anagrafica" value="Nuovo" />
</form>
</div>
views.py
def anagrafica_new(request):
if request.method == 'GET':
form = AnagraficaForm()
sub = 'Nuovo soggetto anagrafica'
dict = {'sub':sub,'form':form}
return render_to_response('anagrafica_form.html', dict, context_instance=RequestContext(request))
urls.py
...
url(r'^anagrafica/new/',('gpf1.views.anagrafica_new')),
...
(http://openpaste.org/05b157c1)
Anyway, i've also tried to remove the () from the callback url.py mapping, but it didnt change nothing.
the request seems to be mapped cause my debug server print this:
"GET /anagrafica/new/? HTTP/1.1" 200 17310
but nothing more. the browser remain on the same page; i also put a print statement just inside the view but it never has been reached. any idea?
thanks,
Luke
As Willian suggested don't put the view in a tuple. Another thing you are missing is the $ at the end of regular expression i.e.:
urls.py
...
url(r'^anagrafica/$','gpf1.views.anagrafica'),
...
url(r'^anagrafica/new/$','gpf1.views.anagrafica_new'),
...
Make sure that the folder containing gpf1 package is within Pythonpath variable (reachable by python).
Edit:
Subsequently I noticed you have a root url map for
url(r'^anagrafica/','gpf1.views.anagrafica')
Since you are missing $ at the end Django will try to map anagrafica/anything here to gpf1.views.anagrafica which is probably not what you want. Consider rereading regular expressions and Django's url mapping documentation as it will make things a bit clearer.
My url is :
1. http://localhost:8000/docs/[slug]
2. http://localhost:8000/docs/[slug]/login
1. url calls before number 2. url I want to send
the slug value to the function mapped by the url 2. In template
what should i wrote for form action event.
I agree, this is nearly incomprehensible, but I'm going to give it a go in terms of an answer.
In terms of calling sequence, there is none. A user might first visit url 2 or url 1. You have no way of guaranteeing which they will try to access first because they might directly input the url into their browser. The only thing you can do is set a variable in request.session's dict and test for it with your login url.
In terms of passing slug to another url, if you're having a url with this in it:
urls = ('',
url(r'docs/(?P<slug>\w+)', 'app.views.slug', name='slug-view'),
url(r'docs/(?P<slug>\w+)/login', 'app.views.slug_login', name='slug-login'),
#..
)
Then in your template you can do this:
<form action="{% url slug-login slugname %}" method="POST">
Your views.py would look something like this.
def slug(request, slug):
#
#
return render_to_response('templatename.html', {'slugname':slug}, context_instance=RequestContext(request))
def slug_login(request, slug):
# do something with slug.
This way, when you access the slug view, you pass into the template a variable called slugname, which the template uses with django's url library to resolve a specifically named url in urls.py with one named parameter, slug, which it will assign the value of slugname.
I suggest you try it.
I might also reccoment you read up on the django url dispatcher. Your use of regex without named parameters is acceptable but really not best practice. I'd also suggest django shortcuts (render_to_response) as a quick way to pass variables into templates and the django template language itself.