Django last visited urls list - python

I'm writing django-based forum, and i've decided it would be suitable for user to browse his last pages. Also, user tracking middleware can be a good aid for suggestions, and so on.
I think, the easiest way to do it is to use the Django Middleware, but i ran into a problem: how to get the title of the page being rendered? Override process_template_response? Can i get the {% block title %} there?
The second server-side way is to use a template tag, i think. In the easiest case, it should should look like {% block title %}{% last_visited _("Page title") %}{% endblock %}.
The third, stupid way: make an ajax script, that will push current user's opened page with title into his session. So, this method will just avoid us getting the page title.
I think, the right way is to get the title block from a template context in middleware. How can i do it?
Thanks.
UPDATE
Made the gist with realisation of the second method using templates and django.cache. The simplest usage:
{% block title %}{% save_visited _("Profile setup") %}{% endblock %}
...
{% load_visited 'visited' %}
{% for title, uri, dt in visited %}
{{ title }} {% trans "at" %} {{ dt }}<br/>
{% endfor %}
Also, i'm still looking for a method allows to get the page's {% block title %} in the middleware. Of course, i can use, i.e., lxml parser and get the title in the process_response method, but it is an ugly overkill.
Thanks for any advice.

In your case i would use the second approach slightly modified:
{% last_visited current_page_title current_page_url num %}
which would do two things:
Store the current title and url in a session variable (list of last visited pages)
Render the num last visited pages from the same session variable

Related

Invalid block tag on line 5: 'else'. Did you forget to register or load this tag? [duplicate]

I would like to have a template that extends another conditionally. Basically, when a variable called "ajax" is true I DO NOT want to have the template extend another.
{% if not ajax %}
{% extends "/base.html" %}
{% endif %}
Any clues?
While you may not wrap extends in logic blocks, since it must be the first tag if used, it can still accept variables, including filters. This should fit your purpose nicely:
{% extends ajax|yesno:"base_ajax.html,base.html" %}
{# stuff #}
Note: the yesno filter also accepts null values (None) as the third choice, and if you do not specify one (as in this case), it will fallback to converting it to False (i.e. it will return the second choice). This allows you to not specify the ajax variable in your template without breaking it.
Suggested by user Rafael:
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
{# stuff #}
This will only work if you are using a RequestContext context instead of a plain Context object and you have the request context processor enabled, or alternatively, if you insert the request object in your template context.
You cannot do it like that. You can however set a variable and use that to choose the template to extend:
{% extends my_template %}
Then in python code you write something like:
if ajax:
template_values['my_template'] = 'base_ajax.html'
else:
template_values['my_template'] = 'base.html'
You may wish to refer to the documentation for more information.
I was looking for the solution of the same problem and came with a bit better workaround than suggested by Klaus Byskov Hoffmann. It is better because you don't have to have 2 separate base templates for ajax and non-ajax requests and, which is more important, you don't have to define if statement that will define which base template to use in EACH controller.
In your case the solution would be:
page.html
{% extends "/base.html" %}
{% block body %}
hello world
{% endblock body %}
base.html
{% if not ajax %}
<html>
<head></head>
<body>
LOGO and other stuff...
{% endif %}{% block body %}{% endblock body %}{% if not ajax %}
FOOTER
</body>
</html>
{% endif %}
So, base.html is always included but it prints its content only when not ajax.
UPDATE: This can be simplified by creating and adding a new ConextProcessor that will populate ajax context variable from the HttpRequest.is_ajax(), so you don't have to do anything extra in your controllers and templates at all.
If you don't want to "extend" a parent template, you can always create an empty file called null.html and extend that. Kind of hacky, but easy to understand.
I know this is an old thread but in case someone stumbles across this, I believe the best way to achieve your goal would be:
"views.py"
if ajax:
request.session['ajax'] = 'ajax'
"base.html"
{% if 'ajax' in request.session %}
{% include "ajax.html" %}
{% endif %}
and in "ajax.html" you wouldn't use any {% extends %} or {% block %} tags since you won't be calling anything for "ajax.html" to extend onto the base. That will be taken care of by "include".

What is a good way to get the dynamic title of a page in Django?

I'm trying to customize a share on Twitter button and I'm using to this to share:
http://twitter.com/intent/tweet?status=[TITLE]+[URL]
I'm able to get the URL with {{ request.get_host }} and {{ request.path }}, but I can't seem to get the title working. Are there any request objects I can use to get the title of my current page title? Thanks.
The easiest way to do this is:
Insert the following code in your base.html
#base.html
{% block title %} {% endblock %}
and following in your index or any Html file with your title
#index.html
{% extends 'base.html'%}
{% block title %} My Page Title {% endblock %}
Place your context object key in double paranthesis.
Lets take am making a dynamic teacher's page in a school management system
#urls.py
path("teacher/<str:pk>/",views.teacher,name="teacher"),
The vew
#view
def teacher(request,pk):
teacher = Teacher.objects.get(id=pk)
context= {"teacher":teacher}
return render(request,'main/teacher.html',context)
The template
<title>{{teacher.fname}} Page</title>

I have problems with setting up django-pagination

I'm making a template for Django site (it's quote database). I wanna have Digg-like pagination. Altough, author of the application has made his own pagination, unfortunately without page numering (just "previous" and "next" links). So I've installed django-pagination, but I can't use it with the site. I'm completly new in Django, even programming - I'm just a simple webdesigner... OK, here we go.
There is the original script: https://bitbucket.org/fleg/fqdb/
The first thing is a problem with template context processors. My settings.py didn't have this section, so I added it exactly like in django-pagination documentation. When I run the site, I get an error: "Put 'django.contrib.auth.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application". So how I have to order that?
A second problem is template. I use it exactly like on the screencast:
{% extends "fqdb/base.html" %}
{% load pagination_tags %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
{% if quotes %}
{% autopaginate quotes %}
{% for quote in quotes %}
{% include 'fqdb/quote_body.html' %}
{% endfor %}
{% paginate %}
{% else %}
<p>Brak cytatów.</p>
{% endif %}
{% endblock %}
But I get "Template error: Caught KeyError while rendering: request". But... Seriously, I don't know what's wrong with this code!
There is the paginated view - quote list. It work without pagination, so I don't think if it's a problem, but maybe.
def list_paged(request, page, order_by_what, title, reverse_name):
hash = get_ip_hash(request)
lista = Quote.objects.filter(accepted = True).order_by(order_by_what)[:]
returnDict = {'quotes': lista, 'title': title, 'hash': hash, 'sidebar': get_sidebar()}
return render_to_response('fqdb/quote_list.html', {'quotes': get_quotes(quotes)}, context_instance=RequestContext(request))
I have modified it to not paginating, because it's django-pagination task. You can find original view on Bitbucket.
Maybe do you know some better pagination solutions?
It looks like you need to add django.contrib.auth.context_processors.auth and django.core.context_processors.request context processors to your TEMPLATE_CONTEXT_PROCESSORS setting.
Before you defined TEMPLATE_CONTEXT_PROCESSORS, django would have used the default. It looks as if some of your code requires the auth processor, hence your first error message.
The KeyError looks to me as if you require the request processor.
Try the following in your settings file:
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
#"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
#"django.core.context_processors.static",
#"django.contrib.messages.context_processors.messages")
"django.core.context_processors.request"
)
I've used the default list given in the Django 1.3 request context docs, added the request processor, and commented out the ones that you don't seem to need.
The order of template context processors does not usually matter, as long as they do not define overlapping variable names.
If the objects are passed from a templatetag
def comment_app(context):
objects = Comments.objects.get_tree_for_object(context['content_object'])
return {
'comments_tree': objects,
'request': context['request']
}
register.inclusion_tag('comments/comment_app.html', takes_context=True)(comment_app)
note the: 'request': context['request']
{% autopaginate quotes N%}
N - how many items you need for each page

Python / Django - If statement in template around extends

I would like to have a template that extends another conditionally. Basically, when a variable called "ajax" is true I DO NOT want to have the template extend another.
{% if not ajax %}
{% extends "/base.html" %}
{% endif %}
Any clues?
While you may not wrap extends in logic blocks, since it must be the first tag if used, it can still accept variables, including filters. This should fit your purpose nicely:
{% extends ajax|yesno:"base_ajax.html,base.html" %}
{# stuff #}
Note: the yesno filter also accepts null values (None) as the third choice, and if you do not specify one (as in this case), it will fallback to converting it to False (i.e. it will return the second choice). This allows you to not specify the ajax variable in your template without breaking it.
Suggested by user Rafael:
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
{# stuff #}
This will only work if you are using a RequestContext context instead of a plain Context object and you have the request context processor enabled, or alternatively, if you insert the request object in your template context.
You cannot do it like that. You can however set a variable and use that to choose the template to extend:
{% extends my_template %}
Then in python code you write something like:
if ajax:
template_values['my_template'] = 'base_ajax.html'
else:
template_values['my_template'] = 'base.html'
You may wish to refer to the documentation for more information.
I was looking for the solution of the same problem and came with a bit better workaround than suggested by Klaus Byskov Hoffmann. It is better because you don't have to have 2 separate base templates for ajax and non-ajax requests and, which is more important, you don't have to define if statement that will define which base template to use in EACH controller.
In your case the solution would be:
page.html
{% extends "/base.html" %}
{% block body %}
hello world
{% endblock body %}
base.html
{% if not ajax %}
<html>
<head></head>
<body>
LOGO and other stuff...
{% endif %}{% block body %}{% endblock body %}{% if not ajax %}
FOOTER
</body>
</html>
{% endif %}
So, base.html is always included but it prints its content only when not ajax.
UPDATE: This can be simplified by creating and adding a new ConextProcessor that will populate ajax context variable from the HttpRequest.is_ajax(), so you don't have to do anything extra in your controllers and templates at all.
If you don't want to "extend" a parent template, you can always create an empty file called null.html and extend that. Kind of hacky, but easy to understand.
I know this is an old thread but in case someone stumbles across this, I believe the best way to achieve your goal would be:
"views.py"
if ajax:
request.session['ajax'] = 'ajax'
"base.html"
{% if 'ajax' in request.session %}
{% include "ajax.html" %}
{% endif %}
and in "ajax.html" you wouldn't use any {% extends %} or {% block %} tags since you won't be calling anything for "ajax.html" to extend onto the base. That will be taken care of by "include".

Render Externally Defined Block In Django Template

I'm writing a simple blog-like application for Django and am trying to get the effect of having a front page with posts limited to 5, with a comprehensive archive that lists something like 100 posts at a time. (100 is not realistic, just throwing a number out there)
Since the blog post blocks will look exactly the same between the two pages minus the number being shown, I'd like to put the corresponding HTML in a separate template that I can include or link to from the actual templates being rendered. I've looked over the documentation, and the include tag looked promising, but it apparently renders outside of the current context, which is not helpful to my cause, since it wouldn't get the objects to loop through. Outside of that, I can't see any other way to do what I want. Is this possible or am I just out of luck and going to have to violate DRY? Code is below to give you an idea of what I want.
Thanks
#######################
# news/frontpage.html #
#######################
{% extends "news/base.html" %}
{% block site_title %} - Front Page{% endblock %}
{% block center_col %}
{{ block.super }}
View Older Blog Posts
{% endblock %}
{% block blog_rows %}
{% for object in object_list %}
# Blog post content would go here, however it is to be included.
{% endfor %}
{% endblock %}
You're looking for an inclusion tag.
Why don't you filter for the blog posts you want to show in your view? That way you can keep the template the same:
{% for object in blogposts %}
# ...
{% endfor %}
You define blogposts in your view, which either includes 5 or 100 posts.
Ignacio is right that you want an inclusion tag, but you should know that the include tag does not render outside the current context - it very definitely uses the same context as the block it's in.
Your problem is probably that you're trying to call blogpost_set on the object_list - but the relationship is not with the list of objects, it's with each individual object in the list. You'd need to iterate through object_list and then through blogpost_set.all on each one.

Categories