How do I list items in my Django models? - django

Am working with django Publisher example, I want to list all the publishers in the db via my list_publisher.html template, my template looks like;
{% extends "admin/base_site.html" %}
{% block title %}List of books by publisher{% endblock %}
{% block content %}
<div id="content-main">
<h1>List of publisher:</h1>
{%regroup publisher by name as pub_list %}
{% for pub in pub_list %}
<li>{{ pub.name }}</li>
{% endfor %}
</div>
{% endblock %}
but when I run "http://127.0.0.1:8000/list_publisher/" the template just prints the page title with no error! What am I doing wrong?

A few suggestions:
check that your base_site.html does define a {% block content %}{% endblock %} section to be refine by your my list_publisher.html
check the cardinality of your list: {%regroup publisher by name as pub_list %}{{ pub_list|length }}. That should at least display the length of your list. If is is '0'... you know why it does not display anything
check that your list is indeed sorted by name before using regroup, or use a {% regroup publisher|dictsort:"name" by name as pub_list %} to be sure
If the length is '0', you have to make sure publisher is defined (has been initialized from the database), and sorted appropriately.
In other word, do you see anywhere (in your template or in the defined templates):
publisher = Publisher.objects.all().order_by("name")
?
(again, the order by name is important, to ensure your regroup tag works properly)

Good answer by VonC.
A quick and dirty way to look at pub_list is to stick [{{pub_list}}] in your template. I put it in square brackets in case it's empty. BTW, you may get something that looks like [,,,,,]. This is because object references are wrapped in <> and your browser is going WTF? Just do a View Source and you'll see the full result.

Related

Get Content of Template Block to Use in IF Statement

Currently I have a block setup for my page titles in my base.html. It takes a unique value from each template page, and adds the website name to the end. For example: ABOUT US - My Site Name. The "ABOUT US" is passed by template and " - My Site Name" appears on every page regardless.
However, I want to use the same base.html on my index page, but only show "My Site Name." I was hoping to use an if statement by parsing the block each template passes to look for a unique value, signifying I am on the index page.
So far my code looks like this:
<title>
{% if {% block title %}{% endblock %} == "index_pg" %}
My Site Name
{% else %}
{% block title %}{% endblock %} - My Site Name
{% endif %}
</title>
obviously this doesn't work. Anyone ideas on how I can accomplish this? Thanks.
Typically I would use two blocks, one wrapped around the other, something like this:
# base.html template
<title>
{% block title %}
{% block inner_title %}{% endblock inner_title %} - The Stock Column
{% endblock title %}
</title>
So for most of your pages, you would extend base.html, and do this:
{% block inner_title %}Page XYZ{% endblock inner_title %}
And then on your index page, you would also extend base.html, but you would then do this:
{% block title %}TEST{% endblock title %}
The resulting output from the first one would be:
<title>Page XYZ - The Stock Column</title>
And the output of the second one, from your index page, would be:
<title>TEST</title>

Extending breadcrumbs with block.super in django using DRY priniples

I am having trouble implementing django_breadcrumbs in a DRY fashion using block.super.
I have a template "editions" that the user can reach in one of two ways: either from home, in which case the user sees all the editions, or from the template "surveys", in which case the user sees only the editions for that survey.
The breadcrumbs for the editions template look like this and they work fine:
{% extends 'base.html' %}
{% load django_bootstrap_breadcrumbs %}
{% block breadcrumbs %}
{{ block.super }}
{% if slug %}
{% breadcrumb "Surveys" "surveys:index" %}
{% breadcrumb "Editions" "editions:index" slug=slug %}
{% else %}
{% breadcrumb "Editions" "editions:index" %}
{% endif %}
{% endblock %}
Disappoinment ensues for pages that hang off the editions template. I had hoped that by extending that page and using block.super, I would inherit the proper breadcrumbs depending on where the edition came from. But I only ever get the Editions breadcrumb even when I hoped for the Surveys / Editions breadcrumbs.
Here is the template "create" which hangs off "edition":
{% extends 'editions/index.html' %}
{% load bootstrap3 %}
{% load django_bootstrap_breadcrumbs %}
{% block breadcrumbs %}
{{ block.super }}
{% breadcrumb "Create" "editions:create" %}
{% endblock %}
I could always put another if: else: in that template, but I would rather just inherit the if: else: from the previous template. What is it I don't understand? Do I need to pass the slug back up to the super:block or something? How would I do that without repeating the same if: else: in the child template? Indeed, how would I do that at even with a new if: else:?
thanks
John
My best guess is that you render the second template without passing the slug variable. Your inheritance is correct, but as the parent (or super) template uses the slug variable, what it renders depends on the variable's contents. Therefore, if no variable called slug is passed, you will always get the else-part of your if statement.
So, the solution seems quite simple: add the slug variable to the context parameter when triggering the template render.

How to create a custom Django template tag working outside of a block?

In my project, I need to treat CSS requirements differently depending on several parameters. Thus, I need an additional level of abstraction compared to available static management systems.
In my templates, I would like to be able to register CSS (and JS) requirements with a template tag which would look like {% register_css 'myfile.css' %}. This approach works like a charm.
However, there is still one problem with this approach : the tag works perfectly when inserted in a block, but never gets called when inserted on top of a child template. The tag definition is:
#register.simple_tag(takes_context = True)
def register_css(context, *args):
context['static_registry'].register_css(streamlet)
return ''
This is my test template:
{% extends main_skelton %}
{% load static_registry %}
{% register_css 'base' %}
{% block title %}Welcome{% endblock %}
{% block content %}
{% register_css 'home' %}
<p>Some content here</p>
{% endblock %}
In that template, the 'home' css gets registered, but not the 'base' one. How may I make both work?
Thanks!
Include an empty {% block init %} in your base template, then override that block in the child templates to register files - {% block init %}{{ block.super }} {% register_css 'foo %}{% endblock %}
The underlying issue is that in a child template, only blocks that match something in the parent template will get rendered. AFAIK there's no easy way around that, but using a dummy block works just fine.

Is there a way to make a block optional in Django template

In Django's templates system, if I have a block that I want to make optional using an if statement, how do I do it?
I was trying this:
{% if val %}{% block title %}Archive {{ foo }}{% endblock %}{% endif %}
But that doesn't work. Is there a way to do that, so that for a given value (in this case Null) the block isn't issued and the base template uses the original values?
Edit:
Let me be a little more specific, so that it is easier to answer.
I have a page with 10 entries per page. The user can then go on to the next page and see the next ten items. For each further page they go, past the first, I would like to have the title tag say something like "Archive 1" or "Archive 10" but if they get back to the original page, it is no longer archive, and it should just go to the original site title already given in the base templates.
I ran into a similar issue with a project I'm working on. Here's how I resolved it using {{ block.super }} to pull the default value from the parent block:
My parent template contains:
{% block title %}Default Title{% endblock %}
My child template contains:
{% block title %}
{% if new_title %}{{ new_title }}{% else %}{{ block.super }}{% endif %}
{% endblock %}
*Note: You may want to wrap the code in {% spaceless %}{% endspaceless %} if you plan to use the result in an HTML title tag.
(It looks like Jordan Reiter posted the same solution in the comments of the original question a bit before my response.)
As far as I understand blocks are placeholders to be "overridden" in the child templates. They have to be defined at "compile time" and not at "run time".
As for your specific problem why not modify the title based on the page number (assuming you use pagination)? Something like this:
{% block title %}
{% ifequal page 1 %}Current{% else %}Archive {{ page }}{% endifequal %}
{% endblock %}
I would only have to add to the good answers above that depending on the Django version sometimes the {{ block.super }} puts the content from the master twice, this seems to happen in the most recent versions of Django.
I am using Django 1.8 and whenever i put the {{ block.super }} it started to behave in that way just as an addition to the Jamie answer i can say that in the base template you can put the content you wish
{% block title %} Default Title {% endblock %}
And then in the child if you want the footer to be inherited and displayed just do not do anything it will be. But if you do not want that block to be displayed then put the tag in the child with empty content just like this:
{% block title %}
{% endblock %}
Then it will be hidden once it is rendered also you can overwrite the content on it if you wish.

Reusing django templates?

I find django's template language very limiting. Following along with django's DRY principle, I have a template that I'd like to use in many other templates. For example a patient list:
{% for physician in physicians.all %}
{% if physician.service_patients.count %}
<div id="tabs-{{ forloop.counter }}">
{% include "hospitalists/patient_list.html" %}
</div>
{% endif %}
{% endfor %}
The problem is that the patient_list template is expecting a list of patients named patients. How can I rename physician.service_patients to patients before including the template?
Thanks,
Pete
Use the with tag:
{% for physician in physicians.all %}
{% if physician.service_patients.count %}
{% with physician.service_patients as patients %}
<div id="tabs-{{ forloop.counter }}">
{% include "hospitalists/patient_list.html" %}
</div>
{% endwith %}
{% endif %}
{% endfor %}
You might also upgrade to creating a custom tag:
{% for physician in physicians.all %}
{% if physician.service_patients.count %}
{% patient-list physician.service_patients %}
{% endif %}
{% endfor %}
Although custom tags involve writing Python code, there are shortcuts that make it easy to use an existing template file as a tag: Django Inclusion Tags
When you have "functionality" (specifically an if-condition) inside a loop, you have an opportunity to move this into the view function.
First
This construct
{% for physician in physicians.all %}
{% if physician.service_patients.count %}
{% endif %}
{% endfor %}
Is so common that you have several ways to avoid it.
Change your model. Add a patients" method and use it instead of the default query set that you get with a on-to-many relationship. This method of your model has theif service_patients.count` test, removing it from your template.
This eliminates the {% if %} from your template, reducing it to {% for %} and the actual HTML, which cannot easily the eliminated.
Change your view function. Write a few lines of code to create a list of physicians with service_patients instead of a simplistic collection of physicians. This code in your view function has the if service_patients.count test, removing it from your template.
This eliminates the {% if %} from your template, reducing it to a {% for %} and the actual HTML, which cannot easily be eliminated.
The point is to get rid of the {% if %} so that you're simply cutting and pasting the {% for %} and the actual HTML. By keeping your template to just the HTML (which cannot be eliminated), the only overhead is the {% for %}
Second
It appears that you want to reuse an {% include %} construct in slightly different contexts.
It's not at all clear what the problem with this {% include %} file is. It is "expecting a list of patients named patients" seems superficially silly. Fix it, so it expects physician.patients.
Perhaps you want to use this same list twice. Once with a list called 'patients' and once with a list called 'physician.patients'. In this case, consider (a) simplifying or (b) writing a template tag.
It appears that you have a patient list that is sometimes a stand-alone page, and other times is repeated many times on a much more complex page. Repeating a list of details embedded in some longer list is not really the best page design. Django doesn't help you with this because -- frankly -- it's not easy for people to use. Hence option (a) -- consider redesigning this "patient list within a physician" list as too complex.
However, you can always write a template tags to create really complex pages.
Summary
There's a really good reason why the Django template language has limited functionality. All of your functionality should be either an essential feature of your model, or a feature of the current application that uses the model.
Presentation is simply the translation of objects (and querysets) into HTML. Nothing more
As way, you can try to use in quality templating language jinja. It is more flexible.