Giter Club home page Giter Club logo

django-render-block's Introduction

Django Render Block

image

image

Render the content of a specific block tag from a Django template. Works for arbitrary template inheritance, even if a block is defined in the child template but not in the parent. Generally it works like render_to_string from Django, but allows you to specify a block to render.

Features

  • Render a specific block from a template
  • Fully supports the Django templating engine
  • Partially supports the Jinja2 engine: it does not currently process the extends tag.

Requirements

Django Render Block supports Django 2.2, 3.1, 3.2, 4.0, and 4.1 on Python 3.7, 3.8, 3.9, and 3.10 (see the Django documentation for which versions of Python are supported by particular Django versions).

Examples

In test1.html:

{% block block1 %}block1 from test1{% endblock %}
{% block block2 %}block2 from test1{% endblock %}

In test2.html:

{% extends 'test1.html' %}
{% block block1 %}block1 from test2{% endblock %}

And from the Python shell:

>>> from render_block import render_block_to_string
>>> print(render_block_to_string('test2.html', 'block1'))
'block1 from test2'
>>> print(render_block_to_string('test2.html', 'block2'))
'block2 from test1'

It can also accept a context as a dict (just like render_to_string), in test3.html:

{% block block3 %}Render this {{ variable }}!{% endblock %}

And from Python:

>>> print(render_block_to_string('test3.html', 'block3', {'variable': 'test'}))
'Render this test!'

API Reference

The API is simple and attempts to mirror the built-in render_to_string API.

render_block_to_string(template_name, block_name, context=None, request=None)

template_name

The name of the template to load and render. If it’s a list of template names, Django uses select_template() instead of get_template() to find the template.

block_name

The name of the block to render from the above template.

context

A dict to be used as the template’s context for rendering. A Context object can be provided for Django templates.

context is optional. If not provided, an empty context will be used.

request

The request object used to render the template.

request is optional and works only for Django templates. If both context and request are provided, a RequestContext will be used instead of a Context.

Exceptions

Like render_to_string this will raise the following exceptions:

TemplateDoesNotExists

Raised if the template(s) specified by template_name cannot be loaded.

TemplateSyntaxError

Raised if the loaded template contains invalid syntax.

There are also two additional errors that can be raised:

BlockNotFound

Raised if the block given by block_name does not exist in the template.

UnsupportedEngine

Raised if a template backend besides the Django backend is used.

Contributing

If you find a bug or have an idea for an improvement to Django Render Block, please file an issue or provide a pull request! Check the list of issues for ideas of what to work on.

Attribution

This is based on a few sources:

django-render-block's People

Contributors

aericson avatar bblanchon avatar clokep avatar cordery avatar evanbrumley avatar jacklinke avatar mixxorz avatar sobolevn avatar vintage avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-render-block's Issues

Look into adding a template tag

StackOverflow 2687173 has an interesting use case using a templatetag that we could easily support:

@register.tag
def include_block(parser, token):
    try:
        tag_name, include_file, block_name = token.split_contents()
    except ValueError:
        raise template.TemplateSyntaxError("%r tag requires a two arguments" % (token.contents.split()[0]))

    #pass vars with stripped quotes 
    return IncludeBlockNode(include_file.replace('"', ''), block_name.replace('"', ''))

class IncludeBlockNode(template.Node):
    def __init__(self, include_file, block_name):
        self.include_file = include_file
        self.block_name = block_name

    def _get_node(self, template, context, name):
        '''
        taken originally from
        http://stackoverflow.com/questions/2687173/django-how-can-i-get-a-block-from-a-template
        '''
        for node in template:
            if isinstance(node, BlockNode) and node.name == name:
                return node.nodelist.render(context)
            elif isinstance(node, ExtendsNode):
                return self._get_node(node.nodelist, context, name)

        raise Exception("Node '%s' could not be found in template." % name)

    def render(self, context):
        t = get_template(self.include_file)
        return self._get_node(t, context, self.block_name)

I am working on a Awesome-Python-HTMX, seeking your feedback

A few of us at PyCon this year got together and brainstormed a new Web Stack that we are calling PyHAT (Python, htmx, ASGI, TailwindCSS). The first thing we set out to do is create awesome-python-htmx; a collection of active tools/libraries/projects in that space. Your project seems like an obvious thing to include, as template fragmenting is extremely helpful in creating hypermedia driven applications.

You don't mention htmx anywhere, did you make this with htmx (or a similar project) in mind?

Template exception handing is broken when rendering a block

When I render a block which causes an exception to be thrown (eg NoReverseMatch from {% url %}), I get a nested exception 'NoneType' object has no attribute 'origin' from the except block in django/template/base.py, line 974, in render_annotated. This becomes the "main" exception shown at the top of the page, making the issue harder to debug.

I'm using django 4.2.3 and python 3.11.

Inheritance more than one level seems to not work

I have three templates

Template A
Template B
Template C

B inherits from A and C inherits from B.

If there is a block in A which I don't specify in C, but try to render the block passing C, it throws a block not found exception.

But it works if I pass in B instead of C.

Utilize Django Template Loaders

I'm not sure if you're aware of a similar project, django-template-partials, which allows users to render partial templates by simply appending the partial name to the template name, e.g. template_name = 'my_template.html#my-partial-name' within a TemplateResponse class-based view. I don't know the specifics of their approach (yet?), but it seems to hook into Django's Template Loaders, and if a given template name contains a #, it splits it and renders the request partial (or block, in your case).

That library does not seem to support template inheritance the way yours does (e.g., with django-render-block I can render a block defined in a parent template, but with django-template-partials it's not possible to render a partial defined in a parent template).

I'd love to be able to use a similar shorthand with your library instead of having to import and call render_block_to_string in each of the response generating methods of a given ClassBaseView.

Template inheritance issue

I'm using django-render-block via django-templated-email 2.2.0 on Django 1.11.7 using python 2.7 and I'm running into an issue when using this layout:

project/application/templates/templated_email/message_base.txt
project/application/templates/templated_email/eng/message-meeting-cancelled.email
project/application/templates/templated_email/eng/message-meeting-cancelled-participants.email

The idea is to render a "generic" meeting cancelled email, via the second template, and include additional detail into more specialised templates. The details are in message-meeting-cancelled-participants.email.

templated_email/message_base.txt has this:

...
{% block subject %}{{ site.name }}: {% block subject_content_block %}{% endblock %}{% endblock %}

{% block plain %}
{% block plain_salutation_block %}Hi,{% endblock plain_salutation_block %}
Best open this message using an app that supports formatted email ;-)

{% block plain_content %}
{% endblock plain_content %}
{% block plain_signature_block %}
Thanks for using our service,
-- {{ site.name }} Admin
{% endblock plain_signature_block %}
{% endblock plain %}
...

templated_email/eng/message-meeting-cancelled.email has some basic information concerning cancellation. The idea is that I'll update that with the detailed template, effectively making this a base template. So here's part of what's in the template:

{% extends 'templated_email/message_base.txt' %}
...
{% block subject_content_block %}Meeting {{ meeting.label }} was just cancelled{% endblock %}

{% block plain_salutation %}Hi {{ participant.first_name | default:'there'}},{% endblock %}

{% block plain_content %}
You have been invited to the "{{ meeting.label }}" meeting at {{ site.name }} {% if confirmed_attendance %}and you confirmed your attendance{% endif %}.

{% block plain_reason_detail %}
{% endblock %}

{% endblock %}
...

templated_email/eng/message-meeting-cancelled-participants.email contains the relevant information for cancelling that meeting:

{% extends 'templated_email/eng/message-meeting-cancelled.email' %}

{% block plain_reason_detail %}
The meeting was scheduled to run at {{ meeting.scheduled_at }}. Too many people were unable to attend to the meeting.
{% endblock %}

Here's the issue when I run the template:

>>> from render_block import *
>>> render_block_to_string('templated_email/eng/message-meeting-cancelled-participants.email', 'plain')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/var/www/brownpapersession/dev/env-brownpapersession/local/lib/python2.7/site-packages/render_block/base.py", line 39, in render_block_to_string
    return django_render_block(t, block_name, context)
  File "/var/www/brownpapersession/dev/env-brownpapersession/local/lib/python2.7/site-packages/render_block/django.py", line 41, in django_render_block
    parent_template, block_name, context_instance)
  File "/var/www/brownpapersession/dev/env-brownpapersession/local/lib/python2.7/site-packages/render_block/django.py", line 74, in _render_template_block
    return _render_template_block_nodelist(template.nodelist, block_name, context)
  File "/var/www/brownpapersession/dev/env-brownpapersession/local/lib/python2.7/site-packages/render_block/django.py", line 106, in _render_template_block_nodelist
    raise BlockNotFound("block with name '%s' does not exist" % block_name)
BlockNotFound: block with name 'plain' does not exist

It does work properly when I run message-meeting-cancelled.email:

from render_block import *
render_block_to_string('templated_email/eng/message-meeting-cancelled.email', 'plain')

Am I missing something?

Support Jinja2 extended templates

#3 added initial support for JInja2, but did not add support for the extends tag. This should be supported (along with using {{ super() }}.

Hook up the Jinja2 template engine

As of Django 1.8 (?) you can use different template engines with Django. Currently django-render-block only works with the Django templating engine, but it could work with other supported engines. Django comes with built-in support for Jinja2 and that should be targeted.

Some work for this is done in the jinja2 branch, but tests involving using extends fail.

Add an installation guide

Hello, it would be really helpful to have an installation guide for newcomers looking to use this project. Adding one would make the onboarding process much smoother.

Wheel for 0.9 on PyPI empty

The wheel released to PyPI a few hours ago does not contain any code, breaking downstreams that use semantic versioning or unlocked dependencies.

Please also consider moving to something >=1.0 so semver works.

TemplateNotFound errors when the same context is passed to django_render_block multiple times

As of 0.8, django_render_block(...) was modified to preserve the original context object if it had the type django.template.Context. Unfortunately, context objects are mutable and this has resulted in odd behaviour if django_render_block is called multiple times with the same context object. In our case, we started seeing TemplateNotFound errors because Django's templating engine skipped templates it thought it had already parsed.

This is a somewhat urgent issue, because django-templated-email has an unpinned dependency on django-render-block and calls django_render_block multiple times with the same context:
https://github.com/vintasoftware/django-templated-email/blob/cba05a7b0f355acdc18174acd1ae468ad77e023d/templated_email/backends/vanilla_django.py#L106

The solution should be as simple as making a deep copy of the context object instead of using it directly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.