Django assignment tag issue - django

For some reason this is returning nothing for me, no errors but just not getting anything returned by the tag.
taglist.py
from django import template
from article.models import Tag
register = template.Library()
#register.assignment_tag
def taglist():
return Tag.objects.values('name').distinct()
base.html
{% load taglist %}
{% block sidebar %}
<ul>
<li>Articles</li>
<li>Admin</li>
{% taglist as mytags %}
{% for t in mytags %}
<li>{{t}}</li>
{% endfor %}
</ul>
{% endblock %}
Any idea whats happening here? The same Tag.objects.... returns what I want it to when done in the shell.

Related

Django ListView not working on the template

I am trying for hours on a problem that seems very straightforward and I tried everything but it's not working. I want to display the list of blogs on a template. So, I have these views:
from django.views import generic
from .models import Blog
class BlogList(generic.ListView):
queryset = Blog.objects.filter()
template_name = 'table_of_contents.html'
context_object_name = 'blog_list'
class BlogDetail(generic.DetailView):
model = Blog
template_name = 'blog.html'
And this is the table_of_contents.html template where I want to display the list of blogs:
{% block table_of_contents %}
<p>Just for test</p>
{{ blog_list }}
{%endblock table_of_contents %}
I expect that would display the queryset string on the frontend, but that's not the case. I debugged BlogList using the Django shell and made sure that queryset was not empty.
What is the (obvious) detail that I am missing here?
Edit:
Here is the blog.html template as well:
{% extends 'base.html' %}
{% block content %}
<p>Test blog template</p>
{% block table_of_contents %} {% include 'table_of_contents.html' %} {% endblock table_of_contents %}
{% endblock content %}
Again, the querystring is not rendered at all, no matter if I use a for loop or just do {{ blog_list }}.
The queryset will look like <QuerySet …>, so that will not render effectively on the page, since it will assume that <QuerySet as a HTML tag, not as content.
What you can do is iterate over the items in the QuerySet, and render these individually, for example:
{% block table_of_contents %}
<p>Just for test</p>
{% for blog in blog_list %}
{{ blog.title }}
{% endfor %}
{%endblock table_of_contents %}
of course here I assume that your Blog model has a title field. You might need to change this to a different field.
If you define a {% block … %} [Django-doc] this means you need to inherit from a parent template that specifies a block with the name table_of_contents.
You thus need to have a parent template, for example:
<!-- parent.html -->
My page
{% block table_of_contents %}
{% endblock table_of_contents %}
in your template where you list the blogs, you thus then inherit from the parent.html page with the {% extends … %}:
{% extends 'path/to/parent.html' %}
{% block table_of_contents %}
<p>Just for test</p>
{% for <b>blog in blog_list</b> %}
{{ blog<b>.title</b> }}
{% endfor %}
{%endblock table_of_contents %}

How to display django-treebeard MP in template as dropdown menu?

Following the treebeard docs api example, I created an annotated_list of my tree using get_annotated_list(parent=None, max_depth=None) with parent=<my root node>. I pass this to my template and using the example they attribute in the docs to Alexey Kinyov, I am able to successfully display my tree using
{% for item, info in annotated_list %}
{% if info.open %}
<ul><li>
{% else %}
</li><li>
{% endif %}
{{ item }}
{% for close in info.close %}
</li></ul>
{% endfor %}
{% endfor %}
What I would like though is to be able to give these nested lists dropdown features. Borrowing from this standard example on w3schools, I modified it to work with my annotated_list template variable and ended up with this:
<ul id="myUL">
<li><span class="caret">{{ annotated_list.0.0 }}</span>
{% for item, info in annotated_list|slice:"1:" %}
{% if info.open %}
<ul class="nested"><li>
{% else %}
</li><li>{% if item.get_children_count > 0 %}<span class="caret">
{% endif %}
{% endif %}
{{ item }}
{% if item.get_children_count > 0 %}</span>
{% endif %}
{% for close in info.close %}
</li></ul>
{% endfor %}
{% endfor %}
</li>
</ul>
My code almost works, but does not seem to display node children for left-most nodes and I can't figure out why.
Note: CSS & JS not included in question but needed to make the dropdown menu work (I'm just using the out-of-the-box CSS/JS used in that w3schools example)
The most likely reason is that there is a problem with the tree.
Run Model.find_problems() to confirm.
Model.fix_tree() can fix most of the common problems.
Note that the get_annotated_list_qs() function doesn't really work at all.
You can try this Code:
<ul id="myUL">
{% for item, info in annotated_list %}
{% if item.get_children_count > 0 %}
<li><span class="box">{{item}}</span><ul class="nested">
{% else %}
<li>{{item}}</li>
{% endif %}
{% for close in info.close %}
</ul>
{% endfor %}
{% endfor %}
</ul>
It worked for me.
To add some missing context:
views.py:
def tree(request):
annotated_list = Category.get_annotated_list()
# template_name = 'JsonDefine/tree.html'
context = {
'annotated_list': annotated_list
}
return render(request, 'JsonDefine/tree3.html',context)
urls.py
from django.urls import path
from . import views
app_name = 'MyApp'
urlpatterns = [
path('tree/', views.tree, name='tree'),
]

django template tag check if image exists

I've got a portion of my app that allows a custom logo.
Default object (and object view) state is no custom logo, but if one exists, replace the header with a custom logo navbar.
logo is a standard ImageField on co(mpany) model:
models.py:
class Co(models.Model):
logo = models.ImageField(blank=True)
template:
{% if co.logo %}
{% block navbar %}
{% include 'templates/navbar_logo.html' %}
{% endblock %}
{% endif %}
I've also tried this with {% if co.logo == None %}, {% if not ... %}, {% if co.logo.url %} and trying to model the logic with co.logo|default_if_none:"" but in instances where a logo isn't set the view throws:
ValueError at /co/foo
The 'logo' attribute has no file associated with it.
for... empty also doesn't work
{% for co.logo.url in co %}
...
{% empty %}
...
{% endfor %}
in django shell:
(with logo)
c.logo >> <ImageFieldFile: logo.png>
c.logo.url >> '/media/logo.png'
(no logo)
b.logo >> <ImageFieldFile: None>
is there a built in django template tag filter that will allow this condition to pass True only if the field has an image uploaded? otherwise don't load the nav block? thanks
I solved this by re-ordering the tags:
{% block navbar %}
{% if co.logo %}
{% include 'templates/navbar_logo.html' %}
{% else %}
{% include 'templates/navbar.html' %}
{% endif %}
{% endblock %}
Try Use 'is not null'
{% if co.logo.url is not null %}
{% block navbar %}
{% include 'templates/navbar_logo.html' %}
{% endblock %}
{% endif %}

Django: with tag outside blocks

It seems like the 'with' tag is not working if it is declared outside of a block as this:
{% extends 'base.html' %}
{% with my_var=1 %}
{% block test1 %}
{{my_var}}
{% endblock %}
{% block test2 %}
{{my_var}}
{% endblock %}
{% endwith %}
The template above simply displays nothing since my_var is NOT passed inside those blocks.
How can I overcome this?
I came to Django from using Tornado with Jinja2 and I was being driven insane by the inability to set variables that (a) could be defined in the template (not view) and (b) would be available in the base template that this derives from. Looking at a little four-line piece of code from django-libs, I was able to rig up something like this that worked well. Here is an example of a title string that should appear in various blocks.
settings.py -- add to TEMPLATES (Django 1.10+)
TEMPLATES = {
...
builtins = ['mysite...wherever...templatetags',]
}
mysite.whereever.templatetags.py
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def setvar(context, key, value):
context.dicts[0][key] = value
return ''
base.html
{% block settings %}
{% comment %}
Put this at the TOP of the template before
any blocks that use variables.
{% endcomment %}
{% endblock settings %}
<html>
<head><title>{{title}}</title></head>
<body><h1>My Site: {{title}}</h1>
{% block body %}
{% endblock body %}
</body></html>
menu.html -- a template that does not set 'title' in views:
{% extends "base.html" %}
{% block settings %}
{{ block.super }} {% comment %}optional{% endcomment %}
{% setvar 'title' 'Menu' %}
{% endblock %}
{% block body %}
<ul><li>Fish</li><li>Steak</li></ul>
{% endblock %}
Now the title will appear in two places in the HTML even though it is defined in the derived template but appears in the top template.

How to redirect back to same page when errors in Django comments

How do you get Django comments to redirect back to the same page where you're filling out a comment if there are errors in the comment submission form?
So basically I have a template like this:
{% block content %}
{% render_comment_form for show %}
{% get_comment_count for show as comment_count %}
<div id="comments-count">
{% if comment_count == 0 %}
No comments yet. Be the first!
{% else %}
Number Of Comments: {{ comment_count }}
{% endif %}
</div>
{% if comment_count > 0 %}
{% render_comment_list for show %}
{% endif %}
{% endblock %}
I created my own list.html and form.html and everything looks fine. In the form.html template there is some code like this:
<ul class="form-errors">
{% for field in form %}
{% for error in field.errors %}
<li>{{ field.label }}: {{ error|escape }}</li>
{% endfor %}
{% endfor %}
</ul>
So obviously, if there is an error in the comment submission form, I would like the user to see the same page as before only with some errors displayed in the comments form. Or alternatively if this is not possible, just ignore the error and instead of transitioning to the preview.html template, it would just not save the comment and again go back to the page.
Any help? Note ideally I dont want to have to create a custom comments app. This functionality should be there already. I know there's a next variable you can pass (and I am doing this), but it only works if the comment form is successful.
you have to use HttpResponseRedirect
from django.http import HttpResponseRedirect
def comment_form(request):
error = request.GET.get('error', None)
requestDict = {'error': error}
return render_to_response('comments.html', requestDict, context_instance=RequestContext(request))
def post_comment(request):
....
your code
....
if something_goes_wrong:
HttpResponseRedirect('project/comment_form/?error=ThereisProblem')
And in template you can do this:
{If error %}
<h1>{{error}}<h1>
{%else%}
render comments...
{%endif%}
Hope this will help you :)