I would like to know if it's possible, with Django, to include a view in another view like:
Declare a view:
def ads(request):
param = ["first_ads_title"]
return render(request, "blog/ads.html", context={"param": param})
With the following html :
<div>ads {{ param[0] }}</div>
And be able to call it from another html view like:
<body>
<h1>hello article {{ article }}</h1>
{% include "blog/ads" %}
</body>
To display first_ads_title in my body ?
Related
I'm not sure if it is variable or tag.
I have two apps (different styles, different navbars) but want to print the same document from db.
I created base.html, templates with extends and everything works perfectly. But.
The body of template is filled from database, which is a part of html code.
And in this code there's <p>The contact email is: blabla#firstapp.example.com</p>
Of course this is wrong for secondapp.
I tried to change body with <p>The contact email is: {{ app_email }}</p>, and set it with context
But it doesn't work - it prints
The contact email is: {{ app_email }}
template/document.html:
{% extends base %}
{% load crispy_forms_tags %}
{% load static %}
{% block head %}
<title>{{ title }}</title>
{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-9">
<h1 class="mt-2">{{ document.header }} !!!</h1>
<hr class="mt-0 mb-4">
{% autoescape off %}
{{ document.body }}
{% endautoescape %}
</div>
</div>
</div>
{% endblock %}
firstapp.views.py:
def myview(request):
context = {
'app_title' : 'First',
'title' : 'First - document',
'app_name' : 'first',
'app_email' : 'contact#first.example.com',
'document' : get_document('document1'),
'base' : 'first/base.html'
secondapp.views.py:
def myview(request):
context = {
'app_title' : 'Second',
'title' : 'Second - document',
'app_name' : 'second',
'app_email' : 'contact#second.example.com',
'document' : get_document('document1'),
'base' : 'second/base.html'
Is it possible this way? Mayby some filter?
edited:
Now I know, that I have to prerender it in get_document. But how to pass unknown parameters?
This function works - but have to add sth do parameters (*args? **kwargs?)
and redefine Context{{ *args? **kwargs?? }}
def get_document(name):
doc = Doc.objects.get(name=name)
doc.body = Template(doc.body).render(Context{{'app-email':'contact#first.example.com'}})
return doc
The problem is you are treating the content of document1 in this case as a context variable itself. It never gets parsed by the django templating engine and so the {{ app_email }} variable is never converted.
I see two options:
if the document is a file from disk (seems like that's not the case based on your description) then you need to figure out how to load the document into your template as another template. I know there are tags for loading another template based on the content of a variable. So you would pass template_name = "template/path/to/document" in your view and then in your template include it with something like {% include template_name %}. Actually, even if the template isn't on disk, you can write a template loader that loads it from where ever.
Alternatively, you can send the results of get_document(...) through the template engine independently. So in the view.py you would render it separately before adding it to the template context. I think there used to be a django.shortcuts.render_string function you could pass it through, though I think that might have changed in newer Django's. Update from OP: Template(<str>).render(<context>) is the way to do it.
Thanks to #saquintes
def get_document(name,**kwargs):
doc = Doc.objects.get(name=name)
doc.body = Template(doc.body).render(Context(kwargs))
return doc
and in first.views.py:
(...)
def myview(request):
context = {
'app_title' : 'First',
'title' : 'First - document',
'app_name' : 'first',
'document' : get_document('document1', app_email = 'contact#first.example.com'),
'base' : 'first/base.html'
(...)
when i add new record from admin panel it should appear in html page , but it doesn't do that
how to fix it
models.py :
class BestArticals(models.Model):
name = models.CharField(max_length=240)
url = models.URLField(default="",max_length=240)
image = models.ImageField(upload_to='images/',null=True, blank=True)
def get_image(self):
if self.image and hasattr(self.image, 'url'):
return self.image.url
else:
return '/path/to/default/image'
def __str__(self):
return self.name
views.py :
from .models import BestArticals
def Best_Articals(request):
best_posts = BestArticals.objects.all()
context = {'best_posts' : best_posts}
return render(request,'android/side_bar_good_posts.html',context=context)
html page :
{% for post in best_posts %}
<div class="card rounded mx-auto d-block" style="width: 18rem;margin-bottom:50px;border-color:#7952b3">
<div class="card-body" id="mobile_design_card">
<p class="card-text" id="mobile_design_card_name">{{ post.name }}</p>
</div>
<img src="{{ post.get_image }}" class="card-img-top" alt="..." height="290px" width="300px">
</div>
{% endfor %}
i didn't add Best_Articals in urls.py because i don't want create url for it , i just want show data in other html page from side_bar_good_posts.html
for example i add this line in other html page :
{% include 'android/side_bar_good_posts.html' %}
Based on your last comment... You should analyze how to works include tag and view function. Let me try to explain me, when you make request to some url, it calls to specific view function and the view return the processed data for this reason when you set url it works.
Include tag only add all text from in it in your file where you use include tag, for this when you add include 'android/side_bar_good_posts.html' only add plain text (html, css, js ) that contains android/side_bar_good_posts.html but in this point this file doesn't contains information about the post because your variable best_posts is empty, nothing call to your Best_Articals view to return best_post. You need to pass the additional context (best_post) to your template.
I.e. {% include "name_snippet.html" with person="Jane" greeting="Hello" %}
Or you could use context processor and then you can use {{best_post}} in all the templates.
I have a template tag that reads values from the URL. For example
the searched term is cancer. After searching, the next page that appears would have a with Searched terms: Cancer. And I would like the value cancer to appear in all of my webpages until the user does a new search.
Pages I have work this way:
Search.html > display.html > explore.html
Search.html is where the user enters what they want to search for.
I have a searchedterms.html which is included into all 3 templates and contains the Javascript code to read from the URL.
By using a JavaScript code, I managed to display searched terms: cancer in display.html but in explore.html the value is empty. I want to be able to save "cancer" to the tag and use it in other templates.
?conditions=cancer
in search.html:
<input required="" type="text" name="conditions">
in display.html:
{% with searched_terms='searchedterms.html' %}
{% include searched_terms %}
{% endwith %}
in explore.html:
{% with searched_terms='searchedterms.html' %}
{% include searched_terms %}
{% endwith %}
in searchedterms.html:
<div id="searched" class="container"></div>
<script type="text/javascript">
var urlParams = new URLSearchParams(window.location.search);
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
var condition = getUrlParameter('conditions');
document.getElementById("searched").innerHTML = "Searched Terms: " + condition;
</script>
Actual results: Cancer appears in display.html but not in explore.html. When display.html is refreshed "cancer" also disappears.
Desired Results: Cancer appears in display.html and explore.html until the user starts a new search.
I think Django Inclusion tag is what you are looking for.
Register your tag in templatetags as below:
#register.inclusion_tag('searchedterms.html')
def searched_terms(query):
return {
'query': query
}
and now in your searchedterms.html file:
<div>
your searched query is: {{ query }} {# display your query here #}
</div>
For Class Based View:
in your Search.html > display.html > explore.html files:
{% load tags %}
{% block content %}
{% searched_terms view.kwargs.conditions %} {# here you pass your kwargs from url #}
<div>some of your existing code. </div>
{% endblock %}
how view.kwargs.conditions work is explained here Access kwargs from a URL in a Django template
For Functional View:
If you want url kwargs in your template from functional views then you can get url kwargs in view and pass it as context data:
def search_view(request, **kwargs):
"""
your existing codes
"""
context = {'conditions': kwargs.get('conditions')}
return render(request, 'search.html', context)
Using request in the template to access from url:
If you want to access the data from url in template then you can also use request.GET or request.POST based on how you want to access the data as in your Search.html > display.html > explore.html files:
{% load tags %}
{% block content %}
{% searched_terms request.GET.conditions %} {# here you access data from url #}
<div>some of your existing code. </div>
{% endblock %}
you can look for django documentation HttpRequest objects for what you can have access with request.
I'm new working with Django and there's something I need to do that looks simple but can't do it yet. Here is the issue, I have the idea to create a big project with a lot of templates and want to have same bar with username include in all templates. So I create a base.html template with some content like the username and some others. Also I have a child.html with another content like a cities list who extends my base.html.
My problem is that when I run my child.html template the views function content in my base.html like the username doesn't show.
Here is what I am doing:
My View for the username :
def userview(request):
a = User.objects.get(pk=1)
return render(request,'base.html',{'a': a})
My base.html template:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css" />
<title>{% block title %}My amazing site{% endblock %}</title>
</head>
<body>
{{a.username}}
<div id="sidebar">
{% block sidebar %}
<ul>
<li>Home</li>
<li>Blog</li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
My view for cities list:
def regionesli(request):
regioneslista = Regiones.objects.all()
return render(request,'child.html',{"resultados": regioneslista})
My Child.html template:
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in resultados %}
<p>{{ entry.nombre_region }}</p>
{% endfor %}
{% endblock %}
If all you want is to print the current user, then a user template variable should be available if the correct template context processor is active. Just call {{ user.username }} in your template. No need to pass a User object into the context. Relevant doc here.
But if for some reason, you have to pass a totally different object, then your cities list view code must also pass the same object. This is because in your sample code, the context variables are not inherited, so you must do something like this.
def userview(request):
a = SomeObject
return render(request,'base.html',{'a': a})
def regionesli(request):
a = SomeObject
regioneslista = Regiones.objects.all()
return render(request,'child.html',{'resultados': regioneslista, 'a': a})
If you want a more DRY way to do it i.e. inherit not only templates but also context variables, then I suggest you study Class-based views. If implemented as such, it will look something like this:
class UserView(TemplateView):
template_name = 'path/to/base.html'
def get_context_data(self, **kwargs):
context = super(UserView, self).get_context_data(**kwargs)
context['a'] = SomeObject
return context
class CitiesListView(UserView):
template_name = 'path/to/child.html'
def get_context_data(self, **kwargs):
# context['a'] will be available once you call the next line
context = super(CitiesListView, self).get_context_data(**kwargs)
context['resultados'] = Regiones.objects.all()
# You can add more context variables here
return context
It may look like more code, but the difference is if the cities list view inherits from the user view, then the context variables are also inherited, and it helps a lot if there are plenty of context variables to inherit.
I have a number of templates that extend base.html. I want the base.html template to house my global navigation and have the text and links in the global navigation be based on a model Division (i.e. the CharField in the model will be used as the button text in the global nav, and the id will be used to build the URL). I thought tags might work, but what I end up with is this (yes, I'm new to Django and Python):
current_tags.py
from django import template
# Import your model
from libs.display.models import Division
from django.db import models
register = template.Library()
#register.simple_tag
def do_get_divisions(self):
d = Division.objects.all()
mylist = []
for each in d:
mylist.append(str(each.DivisionValue))
return my list
I'm attempting just getting the text value in each object to print at this point because I can't get or work with the objects in the template, as you'll see below.
base.html
<!DOCTYPE html>
<html>
<head>
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}style.css" />
</head>
<body>
{% load current_tags %}
<p>{% do_get_divisions "" %}</p> **THIS ACTUALLY PRINTS mylist**
{% for each in do_get_divisions %} **THIS DOESN'T PRINT ANYTHING**
<p>{{ each }}</p>
{% endfor %}
{% block content %}
{% endblock %}
</body>
</html>
I'm sure there is a better way to do global nav based on a model in Django. I basically want to get all the Division objects and put them into a <ul> to use as my global nav in base.html. I am not that familiar with Django, but my views.py don't help me because I am rendering other templates, not base.html, which are extending base.html. For what it's worth, here's one views.py, where /display/info.html template extends base.html:
# Create your views here.
from django.http import HttpResponse
from apps.pulldata.models import Data
from django.shortcuts import render, get_object_or_404
from django.http import Http404
def info(request, group_id):
group = get_object_or_404(Data, pk=group_id)
s = group.XInGroup.all()
return render(request, 'display/info.html', {'Group': group, 's': s})
You cannot put a templatetag into another. Your for-loop is a templatetag that expects the name of an element in your context to iterate over.
If you want to handle the navigation in a template tag you should consider using inclusion tags.
Inclusion tags are functions that use templates to render their data.
A very basic implementation could look something like this:
tags.py
#register.inclusion_tag('navigation.html')
def navigation(selected_id=None):
return {
'navigation': Division.objects.all(),
'selected':selected_id,
}
In your templatetag file you create a dictionary with the navigation items and optionally the currentl selected item to highlight this navigation element.
navigation.html
<ul>
{% for item in navigation %}
<li{% if item.id == selected %} class="selected"{% endif %}>
{{ item.DivisionValue }}
</li>
{% endfor %}
</ul>
the navigation.html uses the dictionary from the python function as context so you start with simply iterating over the navigation.
base.html
{% navigation %}
or
{% navigation current_division.id %}
In the base.html you call the inclusion tag like a normal template tag. if you want to highlight the current item you add its id as a argument.