Include a view in a template - python

In django I have a view that fills in a template html file but inside the html template I want to include another view that uses a different html template like so:
{% block content %}
Hey {{stuff}} {{stuff2}}!
{{ view.that_other_function }}
{% endblock content %}
Is this possible?

Yes, you need to use a template tag to do that. If all you need to do is render another template, you can use an inclusion tag, or possibly just the built in {% include 'path/to/template.html' %}
Template tags can do anything you can do in Python.
https://docs.djangoproject.com/en/3.0/howto/custom-template-tags/
[Followup]
You can use the render_to_string method:
from django.template.loader import render_to_string
content = render_to_string(template_name, dictionary, context_instance)
You'll either need to resolve the request object from the context, or hand it in as an argument to your template tag if you need to leverage the context_instance.
Followup Answer: Inclusion tag example
Django expects template tags to live in a folder called 'templatetags' that is in an app module that is in your installed apps...
/my_project/
/my_app/
__init__.py
/templatetags/
__init__.py
my_tags.py
#my_tags.py
from django import template
register = template.Library()
#register.inclusion_tag('other_template.html')
def say_hello(takes_context=True):
return {'name' : 'John'}
#other_template.html
{% if request.user.is_anonymous %}
{# Our inclusion tag accepts a context, which gives us access to the request #}
<p>Hello, Guest.</p>
{% else %}
<p>Hello, {{ name }}.</p>
{% endif %}
#main_template.html
{% load my_tags %}
<p>Blah, blah, blah {% say_hello %}</p>
The inclusion tag renders another template, like you need, but without having to call a view function. Hope that gets you going. The docs on inclusion tags are at: https://docs.djangoproject.com/en/3.0/howto/custom-template-tags/#inclusion-tags

Using your example and your answer to Brandon's response, this should work for you then:
template.html
{% block content %}
Hey {{stuff}} {{stuff2}}!
{{ other_content }}
{% endblock content %}
views.py
from django.http import HttpResponse
from django.template import Context, loader
from django.template.loader import render_to_string
def somepage(request):
other_content = render_to_string("templates/template1.html", {"name":"John Doe"})
t = loader.get_template('templates/template.html')
c = Context({
'stuff': 'you',
'stuff2': 'the rocksteady crew',
'other_content': other_content,
})
return HttpResponse(t.render(c))

Someone created a template tag that loads a view. I've tried it, and it works. The advantage of using that template tag is that you don't have to rewrite your existing views.

Related

Why am i getting the TypeError:context must be a dict rather than Context. Django

Trying to setup a webpage to list the tags for startups (following along in Django unleashed). The book uses Django 1.8, and Im using 3.0. There are spots where ive seen deprecated functions in the book and was able to find what the updated replacement was, but i cant figure out why django is giving me this error when loading the homepage. Still kinda new at Python and Django. I do have tags created, when executing Tag.objects.all() and one startup has been saved to the database which has its related tag.
Views.py
from django.shortcuts import render
from django.http.response import HttpResponse
from .models import Tag
from django.template import Template, Context, loader
def homepage(request):
tag_list = Tag.objects.all()
template = loader.get_template('organizer/tag_list.html')
context = Context({'tag_list':tag_list})
output = template.render(context)
return HttpResponse(output)
Tag_list.html
{% extends parent_template|default:"organizer/base_organizer.html" %} #An alternative reference to "base.html"
{% block title %}
{{ block.super }} - Tag List
{% endblock %}
{% block content%}
<h2>Tag List</h2>
<ul>
{% for tag in tag_list %}
<li>
<a href="">
{{ tag.name|title }}</a>
</li>
{% empty %}
<p><em>There are currently no Tags available.</em></p>
{% endfor %}
</ul>
{% endblock %}
TypeError at /
context must be a dict rather than Context.
Request Method: GET
Request URL: http://127.0.0.1:8000/
Django Version: 3.0
Exception Type: TypeError
Exception Value:
context must be a dict rather than Context.
Exception Location: C:\Users\Antho\Desktop\suorganizer\su_env\lib\site-packages\django\template\context.py in make_context, line 270
Python Executable: C:\Users\Antho\Desktop\suorganizer\su_env\Scripts\python.exe
Python Version: 3.7.5
Python Path:
You should pass context variables as dict objects to the template as below,
def homepage(request):
tag_list = Tag.objects.all()
template = loader.get_template('organizer/tag_list.html')
context = {'tag_list': tag_list} # update this line
output = template.render(context)
return HttpResponse(output)
Also, you could rewrite the view by using render() function
def homepage(request):
tag_list = Tag.objects.all()
context = {'tag_list': tag_list}
return render(request, 'organizer/tag_list.html', context)

Django template tags forloop

I have created a template tag and trying to loop through the results from the template tag
but I don't get any results
tags.py
from django import template
from loadprograms import dbcontext
register = template.Library()
#register.simple_tag
def get_category():
x = dbcontext.DBContext()
results = x.executequery("Select name from Categories")
categories = [each[0] for each in results]
return categories
template code
{% load category_tags %}
{% get_category %}
{% for each in get_category %}
{{ each }}
{% endfor %}
The {% get_category %} prints all the categories without any issues but the for loop stmt
that loop through the results does not work
What could be the problem?
To make this change in your tag, you'll have to set a variable in the context, but if your objective is to have a list of categories available in templates, just like you would have passed it in from the view - then you need to write a template context processor, which will allow all views to have this variable in their context.
A template context processor is just a method that adds to the request context, by returning a dictionary. Think of it like a view function, that just returns a context.
from .models import Categories
def cat_names(request):
return {'category_names': Category.objects.values_list('name', flat=True)}
To activate this context processor, you have to do a few things:
Add the above code to a file called template_processors.py in the same place as your models.py and views.py.
In your settings.py, add the fully-qualified name of the method to the TEMPLATE_CONTEXT_PROCESSORS setting, making sure you don't override the defaults. To do this easily, import the default settings first, then add to it:
from django.conf.default_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
TEMPLATE_CONTEXT_PROCESSORS = TCP + ('yourapp.template_processors.cat_names',)
Use the render shortcut, which will make sure the context is correctly passed.
In your views, you can now just do this:
from django.shortcuts import render
def home(request):
return render(request, 'home.html')
In your home.html, you can now do:
{% for name in category_names %}
{{ name }}
{% endfor %}

Is there a simple way to display mysql data in Django template without creating an app?

I have a table in my MySQL database named mysite_categories, there are 4 columns but for my purposes I just need two (name, base_url).
I currently have a template '*base_categories.html*' that I use to load the categories manually.
base_categories.html (trimmed down)
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
<li>Art</li>
<li>Biography</li>
<li>Science</li>
</ul>
</div>
{% endblock %}
What I'd like to do is pull the data from the db and use it in a for loop. Something like:
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% for category in mysite_categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
</div>
{% endblock %}
This is probably a newbie question but is it possible to something like this without creating an app?
*EDIT 1*
These are my app files, I'll admit this is probably junk, I have tried so many edits from so many different posts I'm sure I've broke it somewhere :P. I was going to remove it and start fresh but I figure I might as well post it to see where I might have gone wrong?
views.py
from django.shortcuts import render_to_response
from categories.models import categoryList
def index(request):
categories = categoryList.objects.all()
extra_context = {"categories": categories}
return render_to_response("myapp/index.html", extra_context)
models.py
from django.db import models
class categoryList(models.Model):
#id = models.IntegerField(unique=True, db_column='ID') # Field name made lowercase.
name = models.CharField(max_length=255L, unique=True)
base_url = models.CharField(max_length=255L, unique=True)
thumb = models.CharField(max_length=1L, unique=True, blank=True)
class Meta:
db_table = 'mysite_categories'
index.html
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% for category in categories %}
<li>{{ category.title }}</li>
{% endfor %}
</ul>
</div>
As mentioned, it's probably junk at this point, if any of you can help me straighten this out it would be appreciated!
*EDIT 2*
base_right_panel.html
{% block content %}
<div style="float: right;">
<div id="base_categories" style="margin: 10px; padding-bottom: 10px;">
{% block base_categories %}
{% include "base_categories.html" %}
{% endblock %}
</div>
</div>
{% endblock %}
*Edit 3*
base_categories.html
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% if categories %}
{% for category in categories %}
<li>{{ category.title }}</li>
{% endfor %}
{% else %}
<p>no data! {{ categories|length }}</p>
{% endif %}
</ul>
</div>
{% endblock %}
*EDIT 4*
(Application name was changed to CategoryList)
CategoryList/views.py
from django.views.generic import TemplateView
from CategoryList.models import CategorylistCategorylist #<-- Changed to match inspectdb result
class IndexView(TemplateView):
template_name="categorylist.html" #<-- Changed name from index.html for clarity
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context["categories"] = CategorylistCategorylist.objects.all()
return context
CategoryList/models.py
from django.db import models
class CategorylistCategorylist(models.Model): #<-- Changed to match inspectdb
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=255L, unique=True)
base_url = models.CharField(max_length=255L, unique=True)
thumb = models.ImageField(upload_to="dummy", blank=True) #<-- Ignored inspectdb's suggestion for CharField
def __unicode__(self):
return self.name
# Re-added Meta to match inspectdb
class Meta:
db_table = 'categorylist_categorylist'
CategoryList/urls.py
from django.conf.urls.defaults import patterns, url, include
from django.contrib import admin
from django.conf import settings
from CategoryList import views
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='categorylist'),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
MySite/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf import settings
from home import views as home_view
from CategoryList import views as index_view
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', home_view.HomeView.as_view(), name="home"),
url(r'^categories/$', index_view.IndexView.as_view(), name='categorylist'),#include('CategoryList.urls')),
url(r'^admin/', include(admin.site.urls)),
#url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
So far I can load the url "localhost:8000/categories" and I will see the list of category names appear on the right side of the screen as expected, but there is no template formatting applied. Inside my "*base_right_panel.html*" file I've tried "{% include "categorylist.html %}" to link directly to the application, which displays the correct template formatting, but displays the "{% else %}" response from "{% if categories %}" instead of the categories? I have tried changing the include to point to "categories/", which works in the browser, but it tells me it cannot find the template?
I'm sooo stumped right now..?
This answer is not meant to disagree with Alasdair's - it's just to add some more information on working with templates.
The core handler of an HTTP request to a Django application is the view. The view receives the HTTP request, as well as any arguments captured from the URL, and is responsible for returning an HttpResponse instance (or an instance of one of its subclasses) which will be returned to the browser.
The view is not bound to use any particular method to create the HttpResponse. Rendering a template to include information derived from the database and from request information or URL arguments is sufficiently common that there's code to support it, like the render shortcut or its mostly obsolete antecedent render_to_response, but this is by no means required. It's perfectly legitimate to have a view directly construct the HttpResponse:
def index(request):
return HttpResponse('This is an index page.')
Or, for very simple HTML:
def index(request):
return HttpResponse('<html><head><title>example</title></head><body>This is an index page.</body></html>')
In practice, I have often created HttpResponse instances directly to return json data or a dynamically created PDF or Excel file.
A simple way to slot information retrieved from the database into your response would be to use Python's built-in string interpolation:
def index(request):
return HttpResponse('Hello, %s' % request.user.email)
Or you could use the advanced string formatting options:
def index(request):
user_names = {}
user_names['first_name'] = request.user.first_name
user_names['last_name'] = request.user.last_name
return HttpResponse('Hello, %(first_name)s %(last_name)s' % user_names)
All this is building up to the point that it doesn't matter how you generate the text contents of your HttpResponse. All that matters is that you return one.
The template system is a powerful and extensible tool for generating text content, but that's all it does. If you look at the template docs about rendering a template, you'll see some examples that are almost exactly the same as the the string interpolation above.
render_to_response was a shortcut that would accept a template and a context and return an HttpResponse with the rendered contents of that template and context. Skipping over its context_instance and content_type parameters for the sake of demonstration, these two code blocks are identical in effect:
def index(request):
t = Template('Hello, {{ first_name }} {{ last_name }}')
c = Context({'first_name': request.user.first_name, 'last_name': request.user.last_name})
response_text = t.render(c)
return HttpResponse(response_text)
Assume a template index.txt exists as defined below, at the top level of an entry in the setting's TEMPLATE_DIRS tuple.
index.txt
Hello, {{ first_name}} {{ last_name}}
Then the view above could be replaced with:
def index(request):
t = get_template('index.html')
c = Context({'first_name': request.user.first_name, 'last_name': request.user.last_name})
response_text = t.render(c)
return HttpResponse(response_text)
Alternatively, you can skip the explicit creation of the context object and rendering of the template into a string thus:
def index(request):
return render_to_response('index.html', {'first_name': request.user.first_name, 'last_name': request.user.last_name})
On more recent versions of Django you should generally use the render shortcut rather than render_to_response - the details are a bit too much to go into if you're still struggling with getting context into your templates.
def index(request):
return render('index.html', {'first_name': request.user.first_name, 'last_name': request.user.last_name})
Of course, part of what makes templates useful is that the rendering engine can perform certain kinds of logic and lookup. I don't actually need to explictly keep looking up first_name and last_name - I can just pass in request as part of my context and look up its attributes in the templates:
index_showing_context.html
Hello, {{ request.user.first_name }} {{ request.user.last_name }}
def index_showing_context(request):
return render('index_showing_context.html', {'request': request})
Even passing in request isn't strictly necessary in that example, because one of the differences between render and render_to_response that I alluded to above is that request is always part of the context for render. But, again, that's an advanced subject.
So for your particular problem, it really doesn't matter where in your templates you render the data you want, as long as you have provided it to your view's context and are rendering the correct template. The template is in effect just a file name used to find and build a string, into which your context will be interpolated.
The {% include %} template tag is one way to mix template fragments into other templates. If I wanted to, I could set mine up like this:
header.html:
<head>
<title>This is a sample title.</title>
</head>
index.html:
<html>
{% include "header.html" %}
<body><p>This is my template body, {{ request.user.first_name }} {{ request.user.last_name }}.</p></body>
</html>
detail.html:
<html>
{% include "header.html" %}
<body><p>This is a detail page, probably for something selected in the context and given the context key 'object'.</p>
<p>{{ object }}</p>
</body>
</html>
That works fine, but it's not the only option. From your question, I see that you're using blocks and template inheritance. A common idiom is to define a base template that all or almost all other templates will inherit from:
base.html
<html>
<head>
<title>{% block title %}Default title{% endblock %}</title>
{% block extra_head_elements %}{% endblock %}
</title>
<body>
{% block body_header %}Standard page header here {% endblock %}
{% block body_content %}{% endblock %}
{% block body_footer %}Standard page footer here {% endblock %}
</body>
</html>
index.html
{% extends "base.html" %}
{% block title %}index {% endblock %}
{% block body_content %}<p>This is my template body, {{ request.user.first_name }} {{ request.user.last_name }}.</p>{% endblock %}
detail.html
{% extends "base.html" %}
{% block title %}detail{% endblock %}
{% block body_content %}<p>This is a detail page, probably for something selected in the context and given the context key 'object'.</p>
<p>{{ object }}</p>
{% endblock %}
So ultimately, I am not quite sure how you should best stitch together your right panel concept because it depends on the way you want your pages to work. If it's going to be present everywhere or almost everywhere, I would recommend putting it into a base template that the rest of your templates will extend. If you want it on exactly one page, just literally include it in that template. If you want it on some but not all pages, a template fragment that you can {% include %} is probably best.
The main thing is to understand how the template engine will compose your {% include %} and {% extends %} tags, and to provide the necessary data to the template's context in your view.
Edit:
If I wanted to have a view and template pair that just retrieved the categories, this is a simple way to lay it out using your example model code and rendering. There are other options.
index.html
<html>
<head><title>Simple category listing</title></head>
<body><p>The categories are:</p>
<ul>
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
</body>
</html>
view:
def index(request):
categories = categoryList.objects.all()
extra_context = {"categories": categories}
return render_to_response("index.html", extra_context)
If I wanted to reuse the category listing on multiple pages, that gets back into the include vs. extends discussion above. Either way, the template will always require your view to pass in categories as a context variable.
You could execute custom SQL directly to fetch categories in your view, and loop through the output in your template. This would not require an app.
If you create a model, you will be able to use the Django queryset api, which is very convenient, e.g.
mysite_categories = Category.objects.all()
This does require you to create an app. However, creating an app is really easy, just use the startapp command.
python manage.py startapp myapp
Once you've created your app, you can use the inspectdb command to inspect your database, and create a model for your mysite_categories table.

Flask and jinja2 include tag

How to do it "include tag" in jinja2. I need to output a block of articles in the base template. And they work in children.
views.py
Articles.query.filter_by(name=name).first()
base.html
{% block content %}
Content base
{% endblock %}
---{{ this_articles_tag }}----
children.html
{% extends 'base.html' %}
{% block content %}
Content children
{% endblock %}
---{{ output Articles }}----
Django in this "include tag", how to do it in jinja2? (Without using context_processor)
If you need to include another template in the template, just use include in Jinja. But if you are talking about template tags (in Django I remember I liked them a lot), then in Flask only your mentioned context_processor is the way to go. Which I think is not a bad thing at all.
Edit:
Easiest way to get context processor registered as a function is pointed in the documentation.
But if you want something more fancy, like dynamic loader or you will load your functrion from different places, then you can define your own decorator function, which basically wraps the function which returns dictionary:
def example_templatetag():
def get_something():
return get_want_you_want_from_db()
return dict(get_something=get_something)
Then where you create your Flask app object you can easily register this function:
app.context_processor(example_templatetag)
And then in a template you can use is like:
{% set data_you_wanted=get_something() %}
{{ data_you_wanted }}
But maybe for you the way mentioned in documentation will be more than enough ;)

How do I access my own template variables from within a custom template tags template?

I am using Django to build a website.
I have a context processor setup that looks something like this:
TEMPLATE_CONTEXT_PROCESSORS = (
...
"mysite.context_processors.mystandardvariables"
)
This adds some standard variables that I like to use in templates, such as SITE_NAME and SITE_ROOT.
I have just created my first custom template tag and I find that I cannot access these standard variables.
I don't get any errors and my page displays ok, it's just that the variable that I want are not available.
To check which variables are available I already used {% debug %}.
My tag looks like this:
#register.inclusion_tag('search/search_snippet.html', takes_context = True)
def search(context):
form = forms.SearchForm()
return {'form': form }
The template for the tag looks like this:
<form action="{{ SITE_ROOT }}search" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit">
</form>
I am including the search tag in my home page like this:
{% extends "base.html" %}
{% load search_tags %}
{% block content %}
{% search %}
{% endblock %}
To answer my own question, I figured out a way to do what I want using a normal template tag rather than an inclusion tag.
#register.tag
def search(parser, token):
return SearchNode()
class SearchNode(template.Node):
def render(self, context):
return render_to_string('search/search_snippet.html',
{ 'form' : forms.FindForm() }, context)
Here I am passing the context through to the function that renders my template to a string.
I would have preferred to implement this as an inclusion tag as it seems like less work, but I wasn't sure how to get it to work.
If anyone knows how to get this working with an inclusion tag please answer and I'll mark your question as the right answer.

Categories

Resources