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
Related
I'm trying to build a website that has products and categories.
When you are on the page of a product, you can click a button to see a list of all the categories it falls under.
You can click another button, that appears on all pages, to see a list of all the categories overall.
In the html page see_all_categories, I wrote a simple block like this:
{% extends 'base.html' %}
{% load staticfiles %}
{% block content%}
{{Category.all}}
{% endblock content %}
I expect to see a messy printout of all the categories but I don't. It doesn't return an error, but it produces nothing, other than the base.html.
What am I doing wrong?
You want to display a list of the categories. I assume your Category model owns an attribute named "title" which is the representation of your Category.
If you're using Django template engine or Jinja2, you can make a for loop inside your template like this :
{% for cat in Category.objects.all %}
{{ cat.title }}
{% endfor %}
As a troubleshooting, I'd suggest you didn't pass your Category model to your template, that is not done automatically. You have to add your model to the context before rendering the template.
As mentionned in the comments, here is doc for template rendering with Django templates.
Django Template Guide
To add your model to the context you can follow this guide.
I don't intend to help you further because I lack of information and that may vary a LOT according to your settings. (Class Based views ? Function based views ? What kind of template are you using... And so on)
I figured out the solution after many long annoying hours of trying everything. I feel dumb but I want to spare the next guy the massive pain in the two-pack.
This is what I did:
In the Views.py, I changed the view function for this page FROM this:
def view_all_categories(request):
context = {'Category' : Category}
return render(request, 'store/see_all_categories.html', context)
TO this
def view_all_categories(request):
all_cats = Category.objects.all().order_by('id')
context = {'all_categories' : all_cats}
return render(request, 'store/see_all_categories.html', context)
and in the page see_all_categories.html itself, I changed it (from the question) TO this:
{% extends 'base.html' %}
{% load staticfiles %}
{% block content%}
{% for cat in all_categories %}
<p>{{ cat.name }}</p>
{% endfor %}
{% endblock content %}
And now it works!!
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
My app's templatetag code is throwing a KeyError for a missing key (page) in the context variable. In my template, I do not refer to context variables with context.variableKeyName, I just refer to variableKeyName (e.g. {% if is_paginated %}). And in my template, I can refer to the key page without any exceptions.
How should I get the context with the keys it needs into my templatetag?
Here are the details:
I am using django-profiles to return a list of some profiles:
url(r'^profiles/$', 'profiles.views.profile_list',
kwargs={ 'paginate_by':10 },
name='profiles_profile_detail'),
which calls this bit of code here:
https://bitbucket.org/ubernostrum/django-profiles..
In my template, I test {% if is_paginated %} before I call a templatetag:
{% if is_paginated %}{% load paginator %}{% paginator 3 %}{% endif %}
( I am using a templatetag inspired from http://www.tummy.com/.../django-pagination/ updated for django 1.3 http://djangosnippets.org/snippets/2680/ )
But this leads to the KeyError for 'paged'.
The documentation (comments in the class) of http://djangosnippets.org/snippets/2680/ says:
Required context variables: paged: The Paginator.page() instance.
It is also used in the template tag:
paged = context['paged']
You need to provide this context variable for this template tag to work. I think your best bet is to copy the code of profiles.views.profile_list view and add this context variable. It's unfortunately still a function-based view - otherwise extending it would have been a lot cleanier and easier.
the right way to code is:
{% paginator v 3 %}
v - variable that contains the db items
So the title is a bit obtuse, I know, but I couldn't think of a more succinct way to state it. Here's the issue:
I've created two proxy models for "user types", both inheriting from django.contrib.auth.User. Each has a custom manager limiting the queryset to items belonging to a particular Group. Specifically, there's a PressUser which is any user belonging to the "Press" group and StaffUser which is any user in any other group than "Press".
The issue is that when I add 'groups' to list_filters on my StaffUsers modeladmin, the resulting filter options are every group available, including "Press", and not just groups available to StaffUsers.
I've research a bit online and came up with a custom filterspec that should produce the behavior I want, but the problem is that the User model's 'groups' attribute is actually a related_name applied from the Group model. As a result, I can't attach my filterspec to 'groups' in my proxy model.
Is there any other way to apply the filterspec? Alternatively, is there a better approach to filtering the items returned by the default filterspec?
So, I was able to solve my own problem. For those that might run into a similar situation, here are the steps:
The approach I took is to modify the change_list.html template and manually filter out the items I didn't want to be included. There's quite a number of changes to make, though.
First, add a changelist_view method to your ModelAdmin:
# myproject/account/admin.py
class StaffUserAdmin(models.ModelAdmin):
...
def changelist_view(self, request, extra_context=None):
groups = Group.objects.exclude(name__in=['Press',]).values_list('name')
extra_context = {
'groups': [x[0] for x in groups],
}
return super(StaffUserAdmin, self).changelist_view(request,
extra_context=extra_context)
Basically, all we're doing here is passing in the filtered list of Groups we want to use into the context for the template.
Second, create a change_list.html template for your app.
# myproject/templates/admin/auth/staffuser/change_list.html
{% extends "admin/change_list.html" %}
{% load admin_list %}
{% load i18n %}
{% load account_admin %}
{% block filters %}
{% if cl.has_filters %}
<div id="changelist-filter">
<h2>{% trans 'Filter' %}</h2>
{% for spec in cl.filter_specs %}
{% ifequal spec.title 'group' %}
{% admin_list_group_filter cl spec groups %}
{% else %}
{% admin_list_filter cl spec %}
{% endifequal %}
{% endfor %}
</div>
{% endif %}
{% endblock filters %}
This one deserves a little explanation. First, the template tag loads: admin_list is used for the default Django template tag responsible for rendering the filters, admin_list_filter, i18n is used for trans, and account_admin is for my custom template tag (discussed in a sec), admin_list_group_filter.
The variable spec.title holds the title of the field that's being filtered on. Since I'm trying to alter how the Groups filter is displayed, I'm checking if it equals 'groups'. If it does, then I use my custom template tag, otherwise, it falls back to the default Django template tag.
Third, we create the template tag. I basically just copied the default Django template tag and made the necessary modifications.
# myproject/account/templatetags/account_admin.py
from django.template import Library
register = Library()
def admin_list_group_filter(cl, spec, groups):
return {'title': spec.title, 'choices' : list(spec.choices(cl)), 'groups': groups }
admin_list_group_filter = register.inclusion_tag('admin/auth/group_filter.html')(admin_list_group_filter)
The only things that I've changed here are adding a new argument to the method called 'groups' so I can pass in my filtered list of groups from before, as well as adding a new key to the dictionary to pass that list into the context for the template tag. I've also changed the template the tag uses to a new one that we're about to create now.
Fourth, create the template for the template tag.
# myproject/templates/admin/auth/group_filter.html
{% load i18n %}
<h3>{% blocktrans with title as filter_title %} By {{ filter_title }} {% endblocktrans %}</h3>
<ul>
{% for choice in choices %}
{% if choice.display in groups %}
<li{% if choice.selected %} class="selected"{% endif %}>
{{ choice.display }}</li>
{% endif %}
{% endfor %}
</ul>
No big surprises here. All we're doing is putting all the pieces together. Each choice is a dictionary with all the values needed to construct the filter link. Specifically, choice.display holds the actual name of the instance that will be filtered by. Obviously enough, I've set up a check to see if this value is in my filtered list of groups I want to show, and only render the link if it is.
So, it's a bit involved but works remarkably well. Just like that, you have a list of filters that is exactly what you want instead of the default ones generated by Django.
I'm going to tell you off the bat that I've never done this before myself, so take it with a grain of salt.
What I'd suggest would be to override get_changelist on your ModelAdmin, to return a custom ChangeList class, which you can define somewhere in your admin module.
Your custom ChangeList class would simply override get_filters, so you can map your custom FilterSpec for the group field.
Another thing that might interest you are patches from the feature request ticket for specifying custom filter specs. The latest patch doesn't work for Django 1.3rc1 yet, although #bendavis78 recently posted that he's working on a new one, but depending on your version of Django it may apply cleanly.
It looks like it barely missed the cut to get included into the 1.3 milestone, so I figure it's going to make it into the trunk as soon as work beings on Django 1.4.
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.