Creating objects/functions within Jinja to better re-use code - python

I'm currently working on a practice blog site to learn more about web development and I am using Flask.
On my site, people can create blog posts and view the posts of others. Obviously, I want to make my code as re-usable as possible. So right now, depending on the page, I am grabbing some number of blog posts in my routes.py, and then passing them into a number of different pages (e.g. home page, profile page, search page).
Each of these pages has its own template since they all look different. However, the code for displaying the blog posts is the same in all of the sites, even though the blog posts themselves may differ. Is there any way in Jinja to create an object or function (e.g. render_as_blog_posts()) to which I could pass in the blog posts to and run in the template? For example:
routes.py
def profile():
blog_posts=profile_blog_posts
return render_template("profile.html",posts=blog_posts)
def search():
blog_posts=search_blog_posts
return render_template("search.html",posts=blog_posts)
profile.html:
<html>
<title>Profile</title>
{{ render_as_blog_posts(blog_posts) }}
</html>
search.html:
<html>
<title>Search</title>
{{ render_as_blog_posts(blog_posts) }}
</html>

I suppose, you're looking for the 'template inheritance' feature of Jinja2: https://jinja.palletsprojects.com/en/2.10.x/templates/#template-inheritance
Basically, you can achieve what you want in the different ways:
Template extension: https://jinja.palletsprojects.com/en/2.10.x/templates/#base-template
In this case you can define base template with common layout, common set of macroses and define special blocks in this template as a points of customization. Then, you can extend this template and fill blocks in the way specific for derived template (see samples by the provided link)
Templates import: https://jinja.palletsprojects.com/en/2.10.x/templates/#import
More specific feature which looks like exactly the same python's one. You can define special template which contains set of macros and then import this template into yours profile.html or search.html:
{% import 'commmon_functions.html' as common %}
Then you can refer functions from this file as a part of common namespace:
{{ common.render_as_blog_posts(blog_posts) }}

Related

Django: Python variable data as background image

Details and Problem:
I am making a website which uses steam's social authentication and API, it saves users data in the database, and makes the session cookie that contains two main data, username and logged in cookies.
The data which the variable contains is the url to the image, which leads me to the problem, i want to show the picture of user on the index page, but css static file would not allow me to use the variable.
so i tried some other options:
Using HTML <style> tag:
<a class="profile_picture" href="/profile" style="background-image: url({{ picture }})"></a> # would not work, as it takes every character as string.
Using HTML <img> tag:
<img class="profilepicture" src="{{ picture }}"></img> # same problem here, takes every character as unicode string.
Question:
Is there any other way to do this with the setup i have? ( Django, CSS, HTML, Python ), i am trying to do this without installing something extra, i have seen sass, but is there still any other possible way?
Can i use <style> or <img> tag to take variable url as background image?, if so how?
It's hard to answer this question without all of the details, but the first issue that comes to mind is that you are most likely referencing your context variable "picture" incorrectly. Again, I'm not sure by your question what exactly you are doing, but perhaps this example will help:
If I have a model named "Person" and that model has 2 fields, "name" and "picture". In my views.py, if I had a function called main:
def main(request):
persons = Person.objects.all()
return render(request, index.html, {"persons":persons } )
This function creates an context variables named persons that will be available in your index.html file. Obviously this is a very loose example, but serves to guide you with the basics. So in your index.html template, you would reference the picture field by doing this:
{% for person in persons %}
{{ person.picture }}
{% endfor %}
Hope that helps.

php/Symfony View Component analog in python/Django

Symfony has very useful feature - view component, this is small action code and template that you could embed anywhere inside view template:
<?php include_component('news') ?>
for example in above code mews component executes query in db and display results as block on a site page.
http://www.symfony-project.org/book/1_0/07-Inside-the-View-Layer#Components
I need something similar for Django to prepare and display login form in each view template.
We can call this a "widget" probably.
I think you're looking for Django's template tags feature. Template tags can make database calls, render partial templates, or do pretty much anything else you need them to do. Your example, as a template tag, might look something like this in your templates:
{% include_component 'news' %}

How to generate lots of redundant ajax elements like checkboxes and pulldowns in Django?

I've been getting lots of answers from stackoverflow now that I'm in Django just by searching. Now I hope my question will also create some value for everybody.
In choosing Django, I was hoping there was some similar mechanism to the way you can do partials in ROR. This was going to help me in two ways. One was in generating repeating indexed forms or form elements, and also in rendering only a piece of the page on the round trip.
I've done a little bit of that by using taconite with a simple URL click but now I'm trying to get more advanced. This will focus on the form issue which boils down to how to iterate over a secondary object.
If I have a list of photo instances, each of which has a couple of parameters, let's say a size and a quantity. I want to generate form elements for each photo instance separately. But then I have two lists I want to iterate on at the same time.
Context:
photos : Photo.objects.all()
and
forms = {}
for photo in photos:
forms[photo.id] = PhotoForm()
In other words we've got a list of photo objects and a dict of forms based on the photo.id.
Here's an abstraction of the template:
{% for photo in photos %}
{% include "photoview.html" %}
{% comment %}
So here I want to use the photo.id as an index to get the correct form. So that each photo has its own form. I would want to have a different action and each form field would be unique. Is that possible? How can I iterate on that? Thanks!
Would it be a with? In Python of course it's form = forms[photo.id] but here?
{% endcomment %}
Quantity: {{ oi.quantity }} {{ form.quantity }}
Dimensions: {{ oi.size }} {{ form.size }}
{% endfor %}
What can I do about this simple case. And how can I make it where every control is automatically updating the server instead of using a form at all?
Thanks!
James
I'm not sure I understand your question, but here's what I think you want, expressed in pseudo-code:
for photo in photos:
form = forms[photo.id]
generate_some_html(photo, form)
Probably the best way to achieve this is with inclusion tags: http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#inclusion-tags . Basically, it's a custom tag that relies on another template, similar to an RoR partial. The details can be found in the link I provided, but what you basically need to do is
create a package names "templatetags" in one of your app directories
create a module in that package. Let's take foo_tags.py for example.
Add the following boilerplate to foo_tags.py:
from django import template
register = template.Library()
Write your custom tag, which implements generate_some_html. Make it take the caller's context:
#register.inclusion_tag('relative/path/to/some/template.html', takes_context=True)
def foo_tag(context):
photo = context['photo'] # loop variable in parent template
form = context['forms'][photo.id]
# further computation that you need in order to setup the
# context for relative/path/to/some/template.html can be
# done here...
return locals()
Use the context returned by foo_tag in relative/path/to/some/template.html.
Add {% load foo_tags %} to the parent template. You should probably put this near the top, the same way you put imports near the top of a .py file.
Use your new custom tag in the parent template:
{% for photo in photos %}
{% foo_tag %}
{% endfor %}
Django doesn't comme with backed AJAX like RAIL, but it let you choose any lib you want to use from the start.
You can do what you want by creating custom widgets and using form media.

CopyBlock tag for Django

How can I write a tag "copyblock" for Django templates?
For such a function:
<title> {% block title %} some title... {% endblock %} </title>
<h1>{% copyblock title %}</h1>
Take a look at the solutions mentioned in this question:
How to repeat a "block" in a django template
Django's template parser doesn't expose blocks by name. Instead, they are organized into a tree structure in the Django Template's nodelist, with rendering pushing and popping on the stack of template nodes. You'll have a nearly impossible time accessing them in the way your example indicates.
The SO link that ars references provides suggestions on the best solutions. Of those solutions, defining a variable in the context (ie: {{ title }} in the spirit of your example) that can be reused is probably the most straightforward and maintainable approach. If the piece you want to duplicate goes beyond a simple variable, a custom template tag is probably the most appealing option.

Rendering JSON objects using a Django template after an Ajax call

I've been trying to understand what's the optimal way to do Ajax in Django. By reading stuff here and there I gathered that the common process is:
formulate your Ajax call using some JavaScript library (e.g., jQuery), set up a URL pattern in Django that catches the call and passes it to a view function
in the Python view function retrieve the objects you are interested in and send them back to the client in JSON format or similar (by using the built in serializer module, or simplejson)
define a callback function in JavaScript that receives the JSON data and parses them, so to create whatever HTML is needed to be displayed. Finally, the JavaScript script puts the HTML wherever it should stay.
Now, what I still don't get is how are Django templates related to all of this? Apparently, we're not making use of the power of templates at all.
Ideally, I thought it'd be nice to pass back a JSON object and a template name, so that the data could be iterated over and an HTML block is created. But maybe I'm totally wrong here...
The only resource I found that goes in this direction is this snippet (769) but I haven't tried it yet.
Obviously, what's going to happen in this case is that all the resulting HTML is created on the server side, then passed to the client. The JavaScript-callback function only has to display it in the right place.
Does this cause performance problems? If not, even without using the snippet above, why not formatting the HTML directly in the backend using Python instead of the front-end?
Many thanks!
UPDATE: please use snippet 942 because it is an enhanced version of the one above! I found that the inheritance support works much better this way..
Hey thanks vikingosegundo!
I like using decorators too :-).
But in the meanwhile I've been following the approach suggested by the snippet I was mentioning above. Only thing, use instead the snippet n. 942 cause it's an improved version of the original one. Here's how it works:
Imagine you have a template (e.g., 'subtemplate.html') of whatever size that contains a useful block you can reuse:
........
<div id="results">
{% block results %}
{% for el in items %}
<li>{{el|capfirst}}</li>
{% endfor %}
{% endblock %}
</div><br />
........
By importing in your view file the snippet above you can easily reference to any block in your templates. A cool feature is that the inheritance relations among templates are taken into consideration, so if you reference to a block that includes another block and so on, everything should work just fine. So, the ajax-view looks like this:
from django.template import loader
# downloaded from djangosnippets.com[942]
from my_project.snippets.template import render_block_to_string
def ajax_view(request):
# some random context
context = Context({'items': range(100)})
# passing the template_name + block_name + context
return_str = render_block_to_string('standard/subtemplate.html', 'results', context)
return HttpResponse(return_str)
Here is how I use the same template for traditional rendering and Ajax-response rendering.
Template:
<div id="sortable">
{% include "admin/app/model/subtemplate.html" %}
</div>
Included template (aka: subtemplate):
<div id="results_listing">
{% if results %}
{% for c in results %}
.....
{% endfor %}
{% else %}
The Ajax-view:
#login_required
#render_to('admin/app/model/subtemplate.html')#annoying-decorator
def ajax_view(request):
.....
return {
"results":Model.objects.all(),
}
Of course you can use render_to_response. But I like those annoying decorators :D
There's no reason you can't return a rendered bit of HTML using Ajax, and insert that into the existing page at the point you want. Obviously you can use Django's templates to render this HTML, if you want.
When you are doing Ajax I don't think you have any use for templates.
Template is there so that you can generate dynamic HTML on the server side easily and hence it provides few programming hooks inside HTML.
In case of Ajax you are passing JSON data and you can format it as you want in Python.
and HTML/document elements will be generated on client side using the JSON by some JavaScript library e.g. jQuery on client side.
Maybe if you have a very specific case of replacing some inner HTML from server side HTML then maybe you can use templates but in that case why you would need JSON?
You can just query the HTML page via Ajax and change inner or outer or whatever HTML.
Templates are for the purpose of presentation. Responding with data in format X (JSON, JSONP, XML, YAML, *ml, etc.) is not presentation, so you don't need templates. Just serialize your data into format X and return it in an HttpResponse.
While templates are indeed just for presentation purposes, it shouldn't matter if you are doing it on the serverside or client side. It all comes down to separating the control logic that is performing an action, from the view logic that is just responsible for creating the markup. If your javascript control logic is having to handle how you are rendering or displaying the HTML, then you might be doing it wrong, but if you isolate that rendering logic to another object or function, and just passing it the data necessary for the render, then you should be fine; it mirrors how we separate our controllers, models and views on the server side.
Take a look at the github project: http://github.com/comolongo/Yz-Javascript-Django-Template-Compiler
It compiles django templates into optimized javascript functions that will generate your presentation html with data that you pass it. The compiled functions are in pure javascript, so there are no dependencies on other libraries. Since the templates are compiled instead of being parsed at runtime, the strings and variables are all already placed into javascript strings that just need to be concatenated, so you get a huge speed increase compared to techniques that require you to do dom manipulation or script parsing to get the final presentation. Right now only the basic tags and filters are there, but should be enough for most things, and more tags will be added as people start making requests for them or start contributing to the project.
You can use jquery.load() or similar, generating the HTML on the server and loading it into the DOM with JavaScript. I think someone has called this AJAH.
Unfortunately, Django templates are designed to be executed server side only. There is at least one project to render Django templates using Javascript, but I haven't used it and so I don't know how fast, well supported or up to date it is. Other than this, you have to either use the Django templates on the server or generate dynamic elements on the client without using templates.

Categories