Django: calling view function without url mapping - django

How do I pass information from an HTML form to my Python code, without having to specify a url mapping? For example, the following code sends data from the form in my 'index.html' template, to the 'myview' mapping, which then calls the 'myview' view function, which finally renders the 'mypage' template...
index.html
<form method="get" action="{% url 'myview' %}">
urls.py
urlpatterns = patterns('',
url(r'^mypage/$', views.myview, name='myview'),
)
views.py
def myview(request):
return render(request, 'myapp/mypage.html')
However, do I really have to have a url mapping for this? What if I do not want to reload another webpage, and I just want to stay in the same 'index.html' page?
I'm just a little confused over how views are actually called, in the case when I want the view to act more like a traditional function, to process some data, rather than to necessarily render a new template.
Thank you!

You always need a URL if you want your browser to call a view. How else would the server know which view to call? The only way is through the URL mapping. Remember that there is no persistent relationship between the browser and the server: the only way they can communicate is through requests to URLs.
You don't always need to render a template, though. A view can return anything, including raw text or JSON.
I don't understand what you mean about not reloading another page. Posting data to the server is a request for another page: that's just how HTTP works. You can certainly choose to post to the same page you're currently on; and in fact that's exactly how forms are processed in the recommended Django pattern. But you still need a URL mapping pointing at that page, in order to get it in the first place as well as to process the submitted dat.

Besides understanding and accepting Daniel Roseman's answer you could also look at these two packages:
Django Rest Franework
jQuery Form Plugin

Related

How does view process data with HTML form?

I am looking at this example.
This is search_form.html
<html>
<head>
<title>Search</title>
</head>
<body>
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
<html>
Urls.py
urlpatterns = [
# ...
url(r'^search-form/$', views.search_form),
url(r'^search/$', views.search),
# ...
]
And views
from django.http import HttpResponse
from django.shortcuts import render
from books.models import Book
def search(request):
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
books = Book.objects.filter(title__icontains=q)
return render(request, 'search_results.html',{'books':books,'query':q})
else:
return HttpResponse('Please submit a search term.')
When GET data is passed into the query string,
/search/?q=paris
what really happens?
The form in HTML is bound or unbound at this point?
I am newbie to Django, it would be nice if someone can explain.
The form is an element in the browser, so Django does not know anything about the form at all. In the <form> tag it is specified what to do in case somebody clicks on the submit button (or the form is submitted in another way, for example by a JavaScript call).
When the form "fires" it depends on the method what will be done. Here the method is GET, so that means that the content of the form is wrapped in the URI (the ?q=paris part). The webbrowser will normally make a new HTTP GET request, but now with the new URI.
Django will listen to the request, and it sees the querystring (the ?q=paris part) and will turn it into a QueryDict. A QueryDict is some sort of dictionary (except that a key can contain multiple values), this will then be the request.GET part. Django will look at the other parts of the URI to determine to which view the request should be "routed" (that is specified in the urls.py file).
Then the view thus will query the request.GET to obtain the string that matches with the 'q' key (here 'paris') and perform the proper logic. In this case it will make a database query and look for Books with 'paris' as a substring in the title. It will then render a HTTP response (probably the template will render the results of the query, so a list of books where for every book, some details are displayed).
The browser thus obtains the response, and then will render this on the screen of the user, so HTML in the response is then translated to a visual page. It can result in extra queries (for example if the page contains <img> tags, the the corresponding images are fetched).
The method of a <form> can also be a POST (and some browsers even support other methods). In that case a HTTP POST request is made, and then the data in the form is encoded in the headers of the HTTP request (so it is not visible in the URI, which can be useful if it for example contains sensitive information). In that case the view can query request.POST, which is a QueryDict as well, to obtain the parameters.
Regardless of the specifics of the form, the idea is that the browser makes a request, and unless the information of the "old" webpage is stored in some form element or in the header, Django has no means to "see" what the state of the page was. In fact it is not necessary to make the request at a certain page. You could for example have requested your.site.com/?q=paris immediately.

Modal forms and Django URLs, how to work?

html
<form action="{% url 'sp_feedback' %}" method="post">
url
url(r'^feedback/$', views.post_feedback, name="sp_feedback"),
views:
return HttpResponseRedirect("")
In using modal forms, how do you, after hitting submit, return to the page?
In my current setup, the browser redirects to nothing. I'm completely confused on what to put in the url regular expressions.
In my current setup, the browser redirects to nothing.
Because you're redirecting to an empty URL:
return HttpResponseRedirect("")
You've to redirect to the url of the page:
return HttpResponseRedirect('/feedback/')
But it is rather better and convenient to use the redirect() shortcut. Because you can pass it the name of the url and Django will automatically make the redirect to the associated url.
Example:
return redirect('sp_feedback')
It is a good practice to avoid using hardcoded urls in your application.
UPDATE
Since you mention that this form is on every page and you'd like to redirect the user back to that page, here's one solution:
Use request.META['HTTP_REFERER'] in your form view to get the referring page, then use that value to make the redirect:
redirect_to = request.META.get('HTTP_REFERER', '/') # if HTTP-Referer header is not present, just redirect to homepage
return HttpResponseRedirect(redirect_to)

Retrieving ID from URL

Django question here. So in my base.html, I have a header. The header has links that go to user specific pages. That is, URL's like: /1234/home, /1234/about, etc. where 1234 is the id of a user. My question is, if I want to create a url pointing to a django view method called home with signature home (request, user=0) where user is a different user from the logged in user, how would I do this in the template? To clarify, I am using Django's {% url ... %} template tag and I can't just do {% url [view_name] request.user.id %} because I want the user id from the url, not the id of the logged in user. Additionally, I would prefer avoiding passing a template variable to get the id of the user in the url because then I would have to do that on every page.
Get the id you want as a kwarg to your view, and pass it as a variable to your template through the context to use in the {url ...}.
If you want to persist a variable across all your templates, look at context processors. They are added to each RequestContext so they are accessible to all templates assuming you use the render shortcut or pass the RequestContext to your template.render.
https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext
https://github.com/django/django/blob/stable/1.5.x/django/core/context_processors.py
There are some default ones that django uses. It's fairly simple to add your own.
I imagine your context processor will look something like
context_processors.py
def id_from_url(request):
# Find url id component in request.path
return { 'url_id' : url_id }
Then just add to your settings file appname.context_processors.id_from_url

How do a specify get_absolute_url() on a view when the model isn't clear?

I have a place in my Django app where I need to construct a callback to my domain after a third-party auth, but I'm stuck on how to do this since that view in question doesn't really map to one model (or rather, the view code references multiple models), and the docs for get_absolute_url() construction and permalinks all reference models.
For instance, in my template I currently have something like:
<a class="btn btn-danger large" href="http://to/third/party?api_key=noneyobiz&cb=http://localhost:8000/signup">Join via Somethingorother</a>
the line for this view in urls.py is:
url(r'^signup/$', 'signup', name="signup"),
I want the hardcoded 'http://localhost:8000/signup' to be dynamic. I'm hoping this functionality doesn't depend on my using generic views. Actually I don't understand why generating a permalink is even tied to models at all, it seems like it should only depend on the urlconf. What am I missing here?
permalink is only for the use case when you are referencing a model directly. To find a non-model-based URL, you can use the url tag - in your case, {% url signup %}.
permalink is a thin wrapper of django.core.urlresolvers.reverse. Its belongs to django.db.models to be a shortcut because we usually write reverse inside get_absolute_url of models. So use reverse here
from django.core.urlresolvers import reverse
path = reverse('signup')
Update
To use absolute URI, you could
hardcode in settings or use something like Site.objects.get_current() w/ the path you get from reverse or url to get the absolute URI, as Daniel suggested.
If your callback URI is in the same domain w/ the view rendering the template, you could rely on request to get actual absolute URI:
request.build_absolute_uri(reverse('signup'))
Furthermore, you may want to escape the URI in template, like {{ absolute_uri|urlencode }}. or in view through urllib.quote or urllib.urlencode

Django: How to include modelform?

{% include 'django.contrib.auth.views.login' %}
I don't want to write everything by hand.. I hate this really, django full of automatic stuff.
Goal is to include registration/login.html into base.html, so that I could have this form in every page
If I include only template itself (registration/login.html), problem appears that "form.login", I mean "form" var is not defined because this one comes from VIEW which called when you going to login url. So how can I call that view MANUALLY with include or at least to grab django.contrib.auth.views.login variables by my self in my own view and pass then to base.html?
P.s. It's not just about login form, I think there will be more situations like this
I have found better solution in #django irc.
They called inclusion tags
I'll give you my code, because I got lot's of problem learning new stuff in django =)
file: templatetags/form_login.py
from django import template
register = template.Library()
from django.contrib.auth.forms import AuthenticationForm
#register.inclusion_tag('registration/login.html')
def form_login():
return { 'form': AuthenticationForm() }
Now you can have your form anywhere, this will prerender template and THAT'S IT! no stupid context processors which requires to modify whole project settings.py, which is really sux if you writing stand alone little application..
If you need login-form on every page
Create a context processor:
def login_form_processor(request):
return {
'login_form': LoginForm(request.POST or None)
}
Add it to settings.CONTEXT_PROCESSORS.
Include the template for login form:
{% with login_form as form %}
{% include "registration/login.html" %}
{% endwith %}
You can also make you form lazy-loading, so form will not be created until it is used for the first time.
from django.utils improt functional
def login_form_processor(request):
create_login_form = lambda: LoginForm(request.POST or None)
return {
'login_form': functional.lazy(create_login_form, LoginForm)
}
But I guess you won't want the lazy-loading feature, because login-form is cheap to initialize.
Reusing views
Concerning the "grabbing variables" part from your question: you cannot grab variable from view. Django view is method which returns response object. You can not get variables from response. However some of views accept extra_context and other attributes. Those attributes allow you to configure those views in urls, or to wrap them with your own view, for example:
def my_login_view(request):
some_extra_data = get_some_data()
extra_context = {
'some_extra_var': some_extra_data
}
return login_view(request, extra_context=extra_context, template="my_template.html")
This is not exactly grabbing the variables from views, more like augmentation of existing views.
If you expect to have more situations like this, do less data-porcessing in views. Call some methods which checks for permissions. Collect some data from context-processors. Return rendered response. Now you can reuse the data in other views.
You can specify the action on the form html to point to the URL that accesses the corresponding view.
If you want a form, say called as login_form always populated in all templates, then put it in the context_processors.
Browsing the code for django.contrib.auth.views, you will see that the variables form, site and *site_name* are passed to the template.
Either you (1) provide your custom registration form or (2) you can just import django.contrib.auth.forms.AuthenticationForm in your view if you want to use it.