Django context error in extended template called by view - python

I'm working in Django 1.11 with Django-Jet template.
Now I need to extend template in order to showing some data retrived from a view. So, I defined my template and my view.
Here is the code:
views.py
from django.shortcuts import render
from django.shortcuts import render_to_response
from django.views.generic import View
from django.template.context import RequestContext
from django.template import Context, Template
class MyView(View):
def get(self, request, *args, **kwargs):
op = str(self.kwargs['op']).strip().lower()
pk = self.kwargs['pk']
if op =='get':
template='frontend/templates/show_my_data.html'
return render_to_response(template,{'foo':'bar'})
else:
return HttpResponse("Not found")
My simple template:
{% extends "admin/base.html" %}
{% load i18n admin_urls static admin_modify %}
{% block content %}
{{ foo }}
{% endblock %}
settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'static/')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
....
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
But when I run a test I get a key error:
Request Method: GET
Request URL: http://127.0.0.1:8000/admin/data_from_db/get/24/
Django Version: 1.11.2
Exception Type: KeyError
Exception Value:
'user'
Exception Location: /home/marco/sviluppo/myapp/myvenv/lib/python3.4/site-packages/django/template/context.py in __getitem__, line 87
Python Executable: /home/marco/sviluppo/myapp/myvenv/bin/python
So, I make some test, and I found that the problem is (maybe) in context variables. This is my base template that I need to be extended:
base.html
.....
{% if user.is_active and user.is_staff %}
{% jet_get_menu as app_list %}
{% if SIDE_MENU_COMPACT %}
{% for app in app_list %}
#print menu
{% endfor%}
.........
If I delete first condition: {% if user.is_active and user.is_staff %} there will be KeyError in {% jet_get_menu as app_list %}.
I'll show you some screen.
Normal admin template:
https://imgur.com/TKmc1mH
View result if I do not delete {% if user.is_active and user.is_staff %} from base.html template
https://imgur.com/BYtnEqM
as you can see the page is totally empty: no menu labels, no login box in top right corner, ecc.
There seems to be no context variables like user, but I do not understand why.

You need to use the render shortcut instead of render_to_response so that context processors are run.
if op == 'get':
template = 'frontend/templates/show_my_data.html'
return render(request, template, {'foo':'bar'})

You need to load jet_tags in every templates, you will be using them:
{% load jet_tags %}

Related

django.template.exceptions.TemplateSyntaxError: Invalid block tag. Did you forget to register or load this tag?

I have a view that has context data and it extends base.html but as I want the context data to be displayed in all templates that extend from base.html and not only the view with the context data I am doing custom template tags with the context inside but I get an error.
view with and without context data:
class HomeView(ListView):
model = Product
context_object_name='products'
template_name = 'main/home.html'
paginate_by = 25
class HomeView(ListView):
model = Product
context_object_name='products'
template_name = 'main/home.html'
paginate_by = 25
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
categories = Category.objects.all()
news = News.objects.all()
context.update({
'categories' : categories,
'news' : news,
})
return context
base.html with and without the custom tag
{% news %}
{% for new in news %}
<p>{{ new.title }}</p>
{% endfor %}
The custom tag file templatetags/news.py
from django import template
from support.models import News
register = template.Library()
#register.inclusion_tag('news.html', takes_context=True)
def news(context):
return {
'news': News.objects.order_by("-date_posted")[0:25],
}
The custom tag file templatetags/news.html
{% for new in news %}
<p>{{ new.title }}</p>
{% endfor %}
File structure:
Project
main
templates/main
base.html
templatetags
news.py
news.html
models.py
urls.py
views.py
...
project
settings.py
...
...
You need to define the python code containing your tag codes in the TEMPLATES variable in settings.py.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
str(BASE_DIR.joinpath('templates'))
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'libraries':{
'tagname': 'appname.news', # your template tag
}
},
},
]
Simple thing, you should load the template tag in news.html template which is registered.
Just load the tag in news.html template:
{% load tag_name %} #Add here tag name to load
Note: Please ensure that template tag setting is added in settings.py file

How Django find correct Template variable from TemplateView

I have this pieces of code:
# newspaper_project/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic.base import TemplateView
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
path('admin/', admin.site.urls),
path('users/', include('users.urls'))
path('users/', include('django.contrib.auth.urls')),
]
# users/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.SignUp.as_view(), name='signup'),
]
# users/views.py
from django.urls import reverse_lazy
from django.views import generic
from .forms import CustomUserCreationForm
class SignUp(generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
<!-- templates/home.html -->
{% block title %}Home{% endblock %}
{% block content %}
{% if user.is_authenticated %}
Hi {{ user.username }}!
<p>logout</p>
{% else %}
<p>You are not logged in</p>
login |
signup
{% endif %}
{% endblock %}
And my question is:
How Django know what model is used in home.html template? (how Django know about "username"?)
In TemplateView i don't specify Model (in this case CustomUser). When we want to access and render database data, we need specify Model class (or in this case Form) in view. And from here Django accesses for template variable. Isn't it?
In your TEMPLATES setting, you have the auth context processor enabled.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
This adds user (the currently logged-in user or an anonymous user if not logged in) and perms (which stores the user's permissions) to the template context.
To setup a URL by doing path('', TemplateView.as_view(template_name='home.html'), name='home') is just about the simplest way to configure a view.
You wouldn't really do anything complicated with that, but you can specify some context variables using extra_context, for example;
path(
'',
TemplateView.as_view(
template_name='home.html',
extra_context={
'page_title': 'Home Page',
}
),
name='home'
)
To keep the urls.py clean you'd likely create another view for your home page and add your context variables that way;
class HomePageView(TemplateView):
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = 'Home Page'
context['user'] = CustomUser.objects.first() # Filter for user here
return context
<!-- templates/home.html -->
{% block title %}{{ page_title }}{% endblock %}
{% block content %}
{% if request.user.is_authenticated %}
Hi {{ request.user.username }}!
The user you were interested in is {{ user.username }}
<p>logout</p>
{% else %}
<p>You are not logged in</p>
login |
signup
{% endif %}
{% endblock %}
You can access the logged in user from the request object like this providing you have the request context processor in your settings;
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'django.template.context_processors.request',
...
],
},
},
]

django_tables2 gives Tag {% querystring %} error although it is included in settings.py

I have this very simple django_tables2 setup that gives this error and I don't understand why (http://django-tables2.readthedocs.io/en/latest/pages/table-data.html#list-of-dicts):
Error:
Tag {% querystring %} requires django.template.context_processors.request to be in the template configuration in settings.TEMPLATES[]OPTIONS.context_processors) in order for the included template tags to function correctly.
settings.py:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(SETTINGS_PATH, 'templates')
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request', # <-- included
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
views.py:
import django_tables2 as tables
from django.views.generic.base import TemplateView
class RenderView(TemplateView):
template_name = "test.html"
def get_context_data(self, **kwargs):
context = super(RenderView, self).get_context_data(**kwargs)
data = [
{'name': 'Bradley'},
{'name': 'Stevie'},
]
table = NameTable(data)
context["table"] = table
return context
class NameTable(tables.Table):
name = tables.Column()
test.html:
{% load render_table from django_tables2 %}
{% render_table table %}
urls.py:
urlpatterns = [
path('', RenderView.as_view(), name='test'),
]
Apparently there is no request property:
def get_context_data(self, **kwargs):
print(self.request)
gives 'RenderView' object has no attribute 'request'
django 2.0.2, python 3.6
Try changing your load tags in your template to:
{% load django_tables2 %}
{% render_table table %}

When used django_tables2, it told me TemplateDoesNotExist

urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.people),
]
views.py
def people(request):
return render(request, 'people.html', {'people': models.Person.objects.all()})
models.py
class Person(models.Model):
name = CharField(verbose_name="full name", max_length=10)
people.html
{% load render_table from django_tables2 %}
{% load static %}
{% render_table people %}
When I run it, it told me TemplateDoesNotExist at /django_tables2/table.html, I don't understand why.
First, make sure that django_tables2 is included in your INSTALLED_APPS setting.
Then, make sure that you have APP_DIRS set to True in your TEMPLATES setting.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [...],
'APP_DIRS': True,
...
},
]

Django Session variables not updating properly

I am trying to figure out how sessions work. Basically I am trying to make a restaurant menu and store ordered food into session for further use. However, I ran into a problem and I cant figure out what might be the problem.
The problem is that if I submit the form 1st time. The success view shows the correct data.
I click Submit (pridat) and it works correctly
The output is:
('2', 1)
Where number 2 is food ID and 1 is the quantity.
Then I go back to the menu and I want to update the quantity to lets say 3
I change quantity (mnozstvo) to 3 and submit
But the output is still:
('2', 1)
The weirdest thing that has me confused is the fact that for example different food, even though it should be generated the same way works and updates just fine.
If I want to "order" multiple things it works fine with some and sometime one or multiple just refuse to update properly. As I am writing this 3 out of 4 works just fine.
('3', 5)('4', 8)('1', 15)('2', 1)
I can change 3-5, 4-8 and 1-15 but the 2-1 just never ever changes.
If I restart the built in django server sometimes different pair does not update properly. This time it is 2-1 but I also had an issue that 3-5 would not update.
So I would be really happy if someone could tell me what am I doing wrong? I know I am not letting django generate form but I rather do it manually in html, but that should not be the problem, should it?
menu.html with form separated for better visibility
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'restaurant/style.css' %}" />
{% if all_food_list %}
<center>
<ul>
<li>Home</li>
<li>Menu</li>
<li style="float:right"><a class="active" href="#about">Objednavka</a></li>
</ul>
<div class="clearfix">
{% for food in all_food_list %}
<div class="div1">
<center>
<img src="{{ MEDIA_URL }}{{ food.picture.url }}" alt="{{ food.name }}">
<h2> {{ food.name}} </h2>
<p>Cena: {{ food.price }}czk</p>
<p>Hmotnost: {{ food.weight}}g</p>
<p>Zlozenie: {{ food.ingredients}}</p>
<form action="/get_food/" method="post">
{% csrf_token %}
Mnozstvo: <input id="test" type="number" name="quantity" min="0" max="30" step="1" value="1">
<input type="hidden" name="food_type" value="{{ food.id }}">
<input type="submit" value="Pridat">
</form>
</center>
</div>
{% endfor %}
TODO: Funkcny formular, view pre objednavku, nastavit limity div-ov.
</div>
</center>
{% else %}
<p>No food available.</p>
{% endif %}
My views.py
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.template import loader
from .models import Food
from .forms import FoodOrder
def index(request):
template = loader.get_template('restaurant/index.html')
request.session.flush()
return HttpResponse(template.render(request))
def menu (request):
all_food_list = Food.objects.order_by('name')
template = loader.get_template('restaurant/menu.html')
context = {
'all_food_list': all_food_list,
}
return HttpResponse(template.render(context, request))
def get_food(request):
if request.method == 'POST':
form = FoodOrder(request.POST)
if form.is_valid():
quantity = form.cleaned_data['quantity']
#Food_type is db food id
food_type = form.cleaned_data['food_type']
#add to the session
request.session[food_type] = quantity
return HttpResponseRedirect('/success/')
else:
return HttpResponseRedirect('/index/')
def success(request):
#just writes the content of session
obsah = request.session.items()
return HttpResponse(obsah)
# Create your views here.
forms.py
from django import forms
class FoodOrder(forms.Form):
quantity = forms.IntegerField()
food_type = forms.IntegerField()
settings.py
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'restaurant.apps.RestaurantConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'iis_project.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'iis_project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = '/static/'
MEDIA_ROOT = 'D:\Škola\IIS\Projekt - Restaurace\media'
MEDIA_URL = '/media/'

Categories

Resources