Django - Passing argument through href for URL dispatcher? - python

So I am working on a website where at some point I do a search and list a list of textbooks on the page. From there I want the user to be able to click on a textbook and each textbook will have it's own details page. I have been trying to work with Django's URL dispatcher but I am having difficulties. Code and description below.
results.html
<table class="table">
{% for items in results %}
<tr><td>{{items.textbook_name}}</td><td>{{items.class_name}}</td><td>{{items.author}}</td><td>{{items.isbn}}</td><td>></td></tr>
{% endfor %}
</table>
Views.py
def textbook(request, text_name):
return render_to_response(
'textchange/textbook.html',
locals(),
context_instance=RequestContext(request)
)
Urls.py
url(r'^results/(?P<text_name>\w+)/$', views.textbook, name="textbook"),
From my understanding I thought I was passing the items.textbook_name as text_name to urls from the html and then views would be called with text_name as an argument but it is not working. I might be a little backwards here. I need the textbook_name from the textbook the user clicks on so on the details page I can display all it's information from the database.
Thanks.

Quick explanation.
Let's say that your url doesn't need text_name parameter, so that:
{% url 'textchange:textbook' %}?text_name={{items.textbook_name}}
will result in:
/results/?text_name=some-name
text_name won't get passed to url tag, it was simply glued on the end of url.
To pass text_name into url, and build proper url, you should do that:
{% url 'textchange:textbook' text_name=items.textbook_name %}
and it will result in url:
/results/some-name/

Related

Django - Would I be able to use template tags for rendering HTML given URL path conditionals?

I have a blog page with the path /articles/. I would like to use conditional statements to reflect HTML renders.
For example, my blog uses a paginator for blog posts. The paginator uses a URL query to retrieve the next page of post objects like so: /articles/?page=2
I would like for the next page to stylize the HTML template differently, hence my reasoning for using a conditional statement.
Here is my template that I use:
{% if request.path == '/articles/' %}
# Render HTML only meant for the above path
{% elif request.path != '/articles/'%}
# Render HTML for paths that are NOT the exact match above, such as pagination URLs,
# search querys, categories filtering, etc...
{% endif %}
My current bug is that I'm only rendering the first statement: if request.path == '/articles/' for everything, even non exact matches.
So this URL path: /articles/?page=2 is rendering: {% if request.path == '/articles/' %} when it should be rendering the elif {% elif request.path != '/articles/'%} due to the not equals sign.
Is the above possible to do with only HTML template tags? I know I can use urls.py and edit views but I'm using wagtail CMS and playing with the template seems like the most easiest thing to do right now.
request.path does not include the '?...' querystring part of the URL, so this is working as designed - the path portion of the URL /articles/?page=2 is /articles/.
Django compiles the querystring into the dictionary request.GET, so one way of doing what you want is to check whether that dictionary is empty or not:
{% if not request.GET %}
request is for the plain URL /articles/
{% else %}
request has a querystring parameter on it
{% endif %}

NoReverseMatch in Django [Newbie]

I've been trying to figure this out for a while now but I feel like I don't know the framework well enough to debug this myself.
Basically I'm creating a little blog style site and I'm trying to create a list of posts which can link to the page to read the post itself.
I have a for loop in my template:
templates/home.py
<h1>Home Page</h1>
<p>welcome to the ven home page, {{ username }}!</p>
Click here to log out
<br>
Click here to create a post
<h2>Posts:</h2>
{% for post in posts %}
<div>
<hr>
<h4>{{post.title}}</h4>
<p>{{post.body}}</p>
<p><i>{{post.tags}}</i></p>
</div>
{% endfor%}
It's the line <h4>{{post.title}}</h4> which is causing the problem. I'm getting the error
Reverse for 'show' with keyword arguments '{'id': 1}' not found. 1
pattern(s) tried: ['posts/(?P<post_id>\\d+)/view/$']
here is my urls file
url(r'^$', views.CreateFormView.as_view(), name='create'),
url(r'^(?P<post_id>\d+)/view/$', views.show_post, name='show')
The create method link works fine
and here is the view which loads the template:
def home(request):
if not request.user.is_authenticated:
return redirect('users:login')
posts = Post.objects.all()
username = request.user.username
return render(request, 'ven/home.html', {'username': username, 'posts':
posts})
If more information is needed then let me know and I will provide it.
All other answers have said that this error is to do with the namespace, but it's working fine with the create link so I'm stumped.
Thanks in advance!
The argument names are mismatching.
You'd want to change <h4>{{post.title}}</h4>
to
<h4>{{post.title}}</h4>
Since in urls.py the show url is defined as '^(?P<post_id>\d+)/view/$'.

Generating a url with the same GET parameters as the current page in a Django template

I have a certain link to a url in a Django template. I would like to grab all the GET parameters of the current page url and add them to the url of the template's link. The current page might have zero GET parameters.
Include the django.core.context_processors.request context processor in your settings.py, then use the request object in your template's links:
<a href="{% url 'my_url' %}?{{ request.META.QUERY_STRING }}">
This will cause links from a page without any GET variables to have a trailing ? but that's harmless. If that's not acceptable, you could test for them first:
<a href="{% url 'my_url' %}{% if request.META.QUERY_STRING %}?{{ request.META.QUERY_STRING }}{% endif %}">
you could pass request.META['QUERY_STRING'] to the template.
You can grab the get params before you render the template and pass them to the template and render them on the correct link.
You could also build a query string from request.GET
The GET parameters of the current request are stored in HTTPRequest.Get.

Django Paginator not working beyond first page

As mentioned in the title, my paginator doesn't show anything when I click to go to a page beyond the first.
First, let me describe my page in general:
Its function is to get a request input from the user specifying the period interval from which he wants to see a bunch of "call records" along with other filters (this is important). So essentially there's a start and end date from the request and I use it to filter my objects.
The link to "page2" is something like: "localhost:8000/?page=2" and redirects to my existing page but without any data. It's obvious now that the link to the next page should include the other parameters such as start_date=xxxx-xx-xx, or else it wouldn't work.
Here's part of my view.py and I took out a lot of lines to make it brief, the code runs fine:
if request.GET:
filter_form = ReportFilterForm(request.GET)
if filter_form.is_valid():
start = filter_form.cleaned_data["start_date"]
end = filter_form.cleaned_data["end_date"]
#a bunch of omitted lines that use the form to filter
paginator = Paginator(queryset, 100)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
call_logs = paginator.page(page)
except (EmptyPage, InvalidPage):
call_logs = paginator.page(paginator.num_pages)
else:
filter_form = ReportFilterForm()
return render_to_response('xxxx.html',
{'queryset': queryset,
'filter_form': filter_form,
'call_logs': call_logs,
})
My template xxxx.html, just the paginator section, which is pretty standard, taken from the documentation:
{% if call_logs.paginator.num_pages %}
<div class="pagination">
<span class="step-links">
{% if call_logs.has_previous %}
<<
{% endif %}
<span class="current">
Page {{ call_logs.number }} of {{ call_logs.paginator.num_pages }}
</span>
{% if call_logs.has_next %}
>>
{% endif %}
</span>
</div>
{% endif %}
My question is how do I get the current window URL using django templates and not javascript?
Thank you.
You could add the full path to the context from the request object if I understand you correctly:
return render_to_response('xxxx.html',
{'queryset': queryset,
'filter_form': filter_form,
'call_logs': call_logs,,
'magic_url': request.get_full_path(),
})
My question is how do I get the
current window URL using django
templates and not javascript? Thank
you.
it's not necessary the right way to do it, but you can check this post
but i will suggest that you shouldn't mix the filter with the pagination.
rather that you can use AJAX when doing filtering you can create a new function that deal with filtering alone or you can just use the same function and test if request.is_ajax(): , like that when a users filter the contain you will have your filter data (start_date,end_date ) in the URL.
and now when a user want to pass to the next page you already have the filtered argument in the url that you can use to create a queryset that will be pass to the Paginator.
And to deal with the javascript not active you can replace AJAX with a simple POST form and just remember don't mix the filtering with the pagination :)
Hope this will Help :)

Django: Redirect to previous page after login

I'm trying to build a simple website with login functionality very similar to the one here on SO.
The user should be able to browse the site as an anonymous user and there will be a login link on every page. When clicking on the login link the user will be taken to the login form. After a successful login the user should be taken back to the page from where he clicked the login link in the first place.
I'm guessing that I have to somehow pass the url of the current page to the view that handles the login form but I can't really get it to work.
EDIT:
I figured it out. I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
EDIT 2:
My explanation did not seem to be clear so as requested here is my code:
Lets say we are on a page foo.html and we are not logged in. Now we would like to have a link on foo.html that links to login.html. There we can login and are then redirected back to foo.html.
The link on foo.html looks like this:
<a href='/login/?next={{ request.path }}'>Login</a>
Now I wrote a custom login view that looks somewhat like this:
def login_view(request):
redirect_to = request.REQUEST.get('next', '')
if request.method=='POST':
#create login form...
if valid login credentials have been entered:
return HttpResponseRedirect(redirect_to)
#...
return render_to_response('login.html', locals())
And the important line in login.html:
<form method="post" action="./?next={{ redirect_to }}">
So yeah thats pretty much it, hope that makes it clear.
You do not need to make an extra view for this, the functionality is already built in.
First each page with a login link needs to know the current path, and the easiest way is to add the request context preprosessor to settings.py (the 4 first are default), then the request object will be available in each request:
settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
)
Then add in the template you want the Login link:
base.html:
Login
This will add a GET argument to the login page that points back to the current page.
The login template can then be as simple as this:
registration/login.html:
{% block content %}
<form method="post" action="">
{{form.as_p}}
<input type="submit" value="Login">
</form>
{% endblock %}
To support full urls with param/values you'd need:
?next={{ request.get_full_path|urlencode }}
instead of just:
?next={{ request.path }}
This may not be a "best practice", but I've successfully used this before:
return HttpResponseRedirect(request.META.get('HTTP_REFERER','/'))
Django's built-in authentication works the way you want.
Their login pages include a next query string which is the page to return to after login.
Look at http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.decorators.login_required
I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
I encountered the same problem. This solution allows me to keep using the generic login view:
urlpatterns += patterns('django.views.generic.simple',
(r'^accounts/profile/$', 'redirect_to', {'url': 'generic_account_url'}),
)
In registration/login.html (nested within templates folder) if you insert the following line, the page will render like Django's original admin login page:
{% include "admin/login.html" %}
Note: The file should contain above lines only.
See django docs for views.login(), you supply a 'next' value (as a hidden field) on the input form to redirect to after a successful login.
You can also do this
<input type="hidden" name="text" value="{% url 'dashboard' %}" />

Categories

Resources