Opened 8 years ago

Closed 7 years ago

Last modified 7 years ago

#27130 closed Cleanup/optimization (wontfix)

Allow using the DjangoTemplates engine without configuring settings

Reported by: Al Johri Owned by: reficul31
Component: Template system Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: yes Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

Using Django Templates in standalone mode raises a AppRegistryNotReady error.

Root Cause: The get_templatetag_libraries method in django.template.backends.django.DjangoTemplates calls the get_installed_libraries method. The get_installed_libraries method calls apps.get_app_configs which raises a AppRegistryNotReady error if used in standalone mode.

Adding a try except around get_installed_libraries is a quick fix that worked for me.

def get_templatetag_libraries(self, custom_libraries):
    """
    Return a collation of template tag libraries from installed
    applications and the supplied custom_libraries argument.
    """
    try:
        libraries = get_installed_libraries()
    except AppRegistryNotReady:
        libraries = {}
    libraries.update(custom_libraries)
    return libraries

Can you advise if this is a reasonable solution? If so, I can submit a PR.

Change History (16)

comment:1 by Al Johri, 8 years ago

Type: UncategorizedBug

comment:2 by Tim Graham, 8 years ago

I'm just browsing the code so I'm not certain, but it looks like that solution wouldn't make any of the built-in template tags and filters available.

in reply to:  2 comment:3 by Al Johri, 8 years ago

Replying to timgraham:

I'm just browsing the code so I'm not certain, but it looks like that solution wouldn't make any of the built-in template tags and filters available.

I'm able to use the safe built-in in my project with this patch applied so I think built-ins are still available?

comment:4 by Tim Graham, 8 years ago

Component: UncategorizedTemplate system
Resolution: invalid
Status: newclosed

Yes, built-ins isn't the correct term. I think you won't be able to load anything from django.templatetags (cache, i18n, etc.)

Anyway, I think you're hitting that exception because you're missing a django.setup() call that's required for standalone usage.

in reply to:  4 comment:5 by Al Johri, 8 years ago

Replying to timgraham:

Yes, built-ins isn't the correct term. I think you won't be able to load anything from django.templatetags (cache, i18n, etc.)

Anyway, I think you're hitting that exception because you're missing a django.setup() call that's required for standalone usage.

Ah, thank you!

Might want to add a note to the documentation similar to this in v1.7: https://docs.djangoproject.com/en/1.7/ref/templates/api/#configuring-the-template-system-in-standalone-mode

comment:6 by Tim Graham, 8 years ago

We don't update the docs for old, unsupported versions. If there's a spot in the stable version docs to update, feel free to send a PR. Thanks.

comment:7 by Aymeric Augustin, 8 years ago

Triage Stage: UnreviewedAccepted

Actually it would be nice -- if it's possible -- for the template engine to be usable, albeit with limited functionality, outside of a Django project, more precisely without having to configure global Django settings.

The cache, i18n, etc. features wouldn't work because they need configuration provided by Django settings. That's an expected limitation of this feature and it could be documented.

The biggest problem I can see is that we have no good way to test this, this Django's tests run with configured settings.

Optimistically accepting this requirement, because I think it's a sane design principle, but without guarantees that it can be met.

This ticket is mostly a matter of figuring out and documenting what can work and what can't work without settings.

comment:8 by Tim Graham, 8 years ago

Resolution: invalid
Status: closednew
Summary: Cannot use Django Templates in Standalone ModeAllow using the DjangoTemplates engine without configuring settings
Type: BugCleanup/optimization
Version: 1.10master

comment:9 by Quentin Fulsher, 7 years ago

Hey all, I'd like to do some work on this and get more familiar with Django's template system. After reading over the thread it sounds like the first step would be to develop some tests to determine which tags need settings configured and which don't. I figure after we have a module of tests running without settings we can figure out how to integrate that into the existing django testing framework.

comment:10 by reficul31, 7 years ago

For testing the code, is it possible to add a method to @override.settings that removes all the settings so that the test case can run without them? Or another solution can be to individually override each setting used by the template tag and set it to NULL and test. Eg. The time filter uses settings.TIME_FORMAT to get the time in the required format. It might be possible to set @setting.override(TIME_FORMAT=NULL) or something similar.
Edit: This might be helpful https://code.djangoproject.com/ticket/20032

Last edited 7 years ago by reficul31 (previous) (diff)

comment:11 by reficul31, 7 years ago

Owner: changed from nobody to reficul31
Status: newassigned

comment:12 by reficul31, 7 years ago

Has patch: set
Needs tests: set
Patch needs improvement: set

comment:13 by Aymeric Augustin, 7 years ago

In fact using django.template.Engine in standalone mode already works:

>>> from django.template import Context, Engine
>>> engine = Engine()
>>> template = engine.from_string("Hello {{ name }}!")
>>> context = Context({'name': "world"})
>>> template.render(context)
'Hello world!'

DjangoTemplates is a thin integration layer for configuring an Engine according to a Django project's settings. It doesn't make sense to remove its dependencies on settings. Just use Engine directly.

The documentation explains the roles of these classes without ambiguity and specifically mentions using the template engine outside of a Django project (meaning without Django settings): https://docs.djangoproject.com/en/1.10/topics/templates/#engine

django.template.Engine encapsulates an instance of the Django template system. The main reason for instantiating an Engine directly is to use the Django template language outside of a Django project.

django.template.backends.django.DjangoTemplates is a thin wrapper adapting django.template.Engine to Django’s template backend API.

For these reasons, I don't see what needs to be done here.

Last edited 7 years ago by Aymeric Augustin (previous) (diff)

comment:14 by reficul31, 7 years ago

Replying to Aymeric:
I read over the docs of the django.template.engine and knew that it worked in standalone mode. I thought the gist of the ticket was to provide DjangoTemplates with that functionality too. I might be wrong but is it a functionality that could cause problems? Eg. For most of my projects I use DjangoTemplates backend and it would be nice if i could test my templates on it.
Again I might be completely wrong.

in reply to:  14 comment:15 by Aymeric Augustin, 7 years ago

Resolution: wontfix
Status: assignedclosed

Perhaps this analogy will help:

django.template.Engine ~ sqlite3.connect
django.template.backends.django.DjangoTemplates ~ django.db.backends.sqlite3.base.DatabaseWrapper

The two live in the same namespace for historical reasons. Moving the implementation of the engine outside of django.template would be backwards incompatible for no significant benefit.

I wrote a large docstring to clarify which modules belong to the standalone template engine and which modules allow using arbitrary backends with a unified API. See also DEP 182.


Replying to reficul31:

I read over the docs of the django.template.engine and knew that it worked in standalone mode.

If you think the docs could state more clearly that this is the API to use if you want to use the Django template engine in standalone mode, let's improve them.

(Since it's hard to figure out how docs that you wrote yourself could be unclear to others, I'm not in the best position to do that.)

I thought the gist of the ticket was to provide DjangoTemplates with that functionality too.

Unfortunately, it was incorrectly accepted based on a misunderstanding. It should have been closed as wontfix. I realized the problem only when I saw your PR.

I might be wrong but is it a functionality that could cause problems?

Yes, it would worsen the problem that the existence of this ticket demonstrates.

Even though the documentation is unambiguous, there's already some confusion between the concepts of "template engine" (any library that can render templates) and "template backend" (a thin integration layer for configuring a template engine from Django settings). Adding to the ambiguity by blurring the roles of Engine and DjangoTemplates would increase confusion.

Eg. For most of my projects I use DjangoTemplates backend and it would be nice if i could test my templates on it.

DjangoTemplates is nothing more than an Engine configured from Django settings. Here's the whole implementation:

    def __init__(self, params):
        params = params.copy()
        options = params.pop('OPTIONS').copy()
        options.setdefault('autoescape', True)
        options.setdefault('debug', settings.DEBUG)
        options.setdefault('file_charset', settings.FILE_CHARSET)
        libraries = options.get('libraries', {})
        options['libraries'] = self.get_templatetag_libraries(libraries)
        super().__init__(params)
        self.engine = Engine(self.dirs, self.app_dirs, **options)

and then there's a couple methods that forward to the corresponding methods on Engine.

If your projet uses Django settings and the DjangoTemplates backend, then your tests should use Django settings as well, and there's no use making DjangoTemplates work without settings.

If your projet doesn't use Django settings and configures an Engine in standalone mode, then you don't use DjangoTemplates, not does it make any sense, since you don't have Django settings.

comment:16 by reficul31, 7 years ago

Thank you Aymeric for taking out the time and explaining the issue. I get the concept now. I guess an upgrade to the docs might help the other users see it more clearly too.

Last edited 7 years ago by reficul31 (previous) (diff)
Note: See TracTickets for help on using tickets.
Back to Top