I am trying to modify the original Django administration template. I successfully managed to add custom content. But I would need this content to appear only when a table in my database is empty. Thus, I would like to pass some content to the template via the view but I cannot find it.
To be more specific, my extended admin template looks like this:
{% overextends "admin/index.html" %}
{% load i18n admin_urls %}
{% block content %}
{{ block.super }}
{% if is_empty %}
This hyperlink appears only when the table is empty
{% endif %}
{% endblock %}
and I would like to pass to the template to the variable is_empty either True or False, depending on whether the table is empty or not.
Any ideas how to do that?
Thanks a lot!
Create a template context processor that calculates the value of is_empty.
# in my_app/context_processors.py
from my_app.models import MyTable
def is_empty(request):
"""Returns a bool depending on whether MyTable is empty"""
return {'is_empty': not MyTable.objects.exists()}
Add your context processor to your template settings (note this step is slightly different for Django < 1.8).
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
...
'OPTIONS': {
'context_processors': [
...
'my_app.context_processors.is_empty',
],
},
},
]
You can then include {{ is_empty }} in any templates rendered with a request context. This includes admin views, generic class based views, and views that use the render shortcut.
Related
I'm putting together a project management website for my team using django. My base template includes a sidebar menu which contains a list of all projects and users, linking to a DetailView for that user or project, respectively.
My problem is that I need to provide the User and Project models to every view so that I can render that sidebar. I know how to add extra context; the problem is that I feel like I'm violating DRY by modifying the context at each level. Is it possible to simply redefine the base TemplateClass so that all child classes—ListView, DetailView, etc.—contain the modified context?
On a related note, if this is a terrible way to set up the project, let me know that as well.
You could use the template context processor:
myapp/context_processors.py:
from django.contrib.auth.models import User
from myapp.models import Project
def users_and_projects(request):
return {'all_users': User.objects.all(),
'all_projects': Project.objects.all()}
And then add this processor to the TEMPLATE_CONTEXT_PROCESSORS setting for Django version < 1.8:
TEMPLATE_CONTEXT_PROCESSORS = (
...
'myapp.context_processors.users_and_projects',
)
And for Django version >= 1.8 add it to the context_processors list in the OPTIONS of the TEMPLATES setting:
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
...
'myapp.context_processors.users_and_projects',
],
},
},
]
Context processor will run for ALL your requests. If your want to run these queries only for views which use the base.html rendering then the other possible solution is the custom assignment tag:
#register.assignment_tag
def get_all_users():
return User.objects.all()
#register.assignment_tag
def get_all_projects():
return Project.objects.all()
And the in your base.html template:
{% load mytags %}
{% get_all_users as all_users %}
<ul>
{% for u in all_users %}
<li>{{ u }}</li>
{% endfor %}
</ul>
{% get_all_projects as all_projects %}
<ul>
{% for p in all_projects %}
<li>{{ p }}</li>
{% endfor %}
</ul>
I want to try and show or hide urls in my navigation page based on user group.
currently i am adding to the top of every view and sending through a value to the template and checking against that, but this doesnt seem too efficient, also if a view does not require auth and that value is not set, will that break the template?
is there a better way to do this?
like a global.py where i could check and set then use it in any template? or something completely different altogether?
view.py
Authorised_user = ''
if request.user.is_authenticated():
Authorised_user = 'IT'
#login_required
def index(request):
return render(request, 'service/index.html', {
'Authorised': Authorised_user,
})
template.html
{% if Authorised == 'IT' or Authorised =='Netwworks' %}
Link
{% endif %}
i do have the user groups in django admin
Based on Get user group in a template
Create user_tags.py / group_tags.py at an appropriate place. e.g. auth_extra/templatetags/user_tags.py
from django import template
register = template.Library()
#register.filter('in_group')
def in_group(user, group_name):
return user.groups.filter(name=group_name).exists()
Then in your template:
{% load user_tags %}
{% if request.user|in_group:"IT"%}
IT only link
{% endif %}
{% if request.user|in_group:"Netwworks"%}
Netwworks only link
{% endif %}
Easiest way around this for me was https://stackoverflow.com/a/17087532/8326187.
Here you don't have to create a custom template tag.
{% if request.user.groups.all.0.name == "groupname" %}
...
{% endif %}
You need to create context_processors.py and create a function say
def foo():
Authorised_user = ''
if request.user.is_authenticated():
Authorised_user = 'IT'
Then in setttings
TEMPLATE_CONTEXT_PROCESSORS = ("path_to_context_processor.foo")
this way you can use foo variable in all the templates without explicitly defining in all the views.
You can also have a look here:https://rubayeet.wordpress.com/2009/10/31/django-how-to-make-a-variable-available-in-all-templates/
I'm trying to set up a Django app that has a MarkupField in it's model, like this:
from django.db import models
from markupfield.fields import MarkupField
class Recipe(models.Model):
instructions = MarkupField(default_markup_type='markdown')
Then I render the field in a Jinja2 template, like this:
{% if recipe.instructions %}
{{ recipe.instructions }}
{% else %}
No instructions have been added yet.
{% endif %}
Rendering of the markdowned text works flawless, but it is placed as a string inside the DOM so the browser doesn't interpret the HTML tags, like you can see here:
I don't feel like I missed something relevant in the django-markupfield's docs, but somehow I need to get rid of this string representation.
Anyone of you guys got an idea? Thanks in advance.
Thanks to #doru's advices I stumbled across the Jinja2 documentation and found the autoescaping statement:
{% autoescape off %}{{ recipe.instructions }}{% endautoescape %}
This one worked for me.
It's even possible to make it work globally by setting the autoescape option to False.
{
'BACKEND': 'django_jinja.backend.Jinja2',
...
'OPTIONS': {
'autoescape': False,
...
}
},
I'm trying to create a custom placeholder to add an admin-editable section on a website. Django-cms' documentation is really generic about what's to be done to add it.
The placeholder lives in a separate app, called contacts, already added to the settings.py file
Here's my code up to now (skipping imports to be less verbose):
models.py
class ContactsPlaceholder(models.Model):
phone = models.CharField(max_length=100)
email = models.CharField(max_length=100)
address = models.TextField(max_length=700)
# your fields
my_placeholder = PlaceholderField('contacts_contactsplaceholder')
# your methods
def __unicode__(self):
return "Contacts Placeholder"
views.py
def contacts(request):
# Load the the contacts from db
contactsfields = ContactsField.objects.all()
contacts_placeholder = ContactsPlaceholder.objects.all()
context = {"contactsfields" : contactsfields, "contacts_placeholder" : contacts_placeholder}
return render(request, "../templates/contacts.html", context)
def contacts_placeholder_detail(request, id): # is this really useful?
object = get_object_or_404(ContactsPlaceholder, id=id)
return render_to_response('../templates/contacts_placeholder_detail.html', {
'object': object,
}, context_instance=RequestContext(request))
contacts.html
{% extends "base.html" %}
{% load cms_tags %}
{% block content %}
<div>
<h1>Contacts</h1>
{% placeholder "contacts_placeholder" or %}
<p>Placeholder is empty</p>
{% endplaceholder %}
</div>
{% endblock content %}
and finally, admin.py
class ContactsPlaceholderAdmin(PlaceholderAdminMixin, admin.ModelAdmin):
# Editable fields
frontend_editable_fields = ("phone", "email", "address")
# Form fields order and sections
fieldsets = [
(None,{"fields" : ["phone", "email", "address"]})
]
admin.site.register(ContactsPlaceholder, ContactsPlaceholderAdmin)
With this configuration, after having run python manage.py syncdb I do get "Placeholder is empty" in the html response, and of course the placeholder is not editable using the standard frontend editor, which was the desired behaviour.
Going to 127.0.0.1:8000/admin/ i can see the "Contacts Placeholder" table, however when I click it or try to add items I do get the following error:
OperationalError at /us/admin/contacts/contactsplaceholder/
no such column: contacts_contactsplaceholder.phone
If the contacts() view is rendered via an app hook then using {% placeholder "contacts_placeholder" %} in the template won't work.
When using Placeholders in apps connected to the CMS via an AppHook you must use {% static_placeholder "MyPlaceholder" %} instead of the usual {% Placeholder "MyPlaceholder" %}
If you've got an app or a plugin in which you've created a PlaceholderField, then in your template which renders that, you'd need the following tag;
{% render_placeholder instance.placeholderfieldname %}
I am a beginner of Django. Now, I have a problem of getting templates. The context of my webpage contains just messy code...
Here is photo/views.py:
from django.template import loader, Context
from django.http import HttpResponse
from final.photo.models import Image, Audio
def List(request):
posts = Image.objects.all()
t = loader.get_template("list.html")
return HttpResponse(t, { 'posts': posts })
Here is photo/urls.py:
from django.conf.urls.defaults import *
from final.photo.views import List
urlpatterns = patterns('',
url(r'^$', List),
)
Here is list.html: (some of the code cannot be seen on the webpage)
<pre>
<title>So Easy! - Scene List</title>
<h1>So Easy! Learn Chinese</h1>
{% block content %}
{% endblock %}
I hope someone can help me solve it! Thanks!
Try changing your view to the following:
def List(request):
posts = Image.objects.all()
context = RequestContext(request, {
'posts': posts,
})
return render_to_response('list.html', context)
Also, check that your settings.py has the following:
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
Finally, you'll also need to change your list.html template to make use of posts variable you're passing by using {{ posts.some_image_attribute }} in your template.
First of all: which version of django are you using? Django 1.3 added View Classes, which make things a lot easier.
Considering you're still on Django 1.2:
You must set the template folder at settings.py:
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
"/absolute/path/to/your/template/folder",
)
Also you need to add a code snippet inside list.html:
{% block content %}
{% for item in posts %}
{% endfor %}
{% endblock %}
It's advised to create a base.html for your templates. After you do this, add {% extends "base.html" %} as the first line of your list.html
The return line of your view function should be:
return render_to_response('list.html', { 'posts' : posts })