Django

Code

Ticket #2539 (assigned)

Opened 2 years ago

Last modified 7 months ago

Custom tags and filters can be restricted by namespace

Reported by: limodou@gmail.com Assigned to: anonymous (accepted)
Component: Template system Version:
Keywords: Cc: me@andy.durdin.net
Triage Stage: Accepted Has patch: 1
Needs documentation: 1 Needs tests: 0
Patch needs improvement: 0

Description

How to use namespace? For example,

{% load example %}
{% example.testtag %}

And I think if the namespace can be optional is better. I don't know if it's useful, but sometimes I read others projects, and as I reading the template, I don't know which tag is in which file. So find the correct tag definition file is somewhat diffcult. If I can add namespace in the front of a custom tag name, it'll be easy to locate the source file.

The maillist discussion thread is HERE

Attachments

template.diff (5.6 kB) - added by limodou on 08/13/06 03:08:37.
template_01.diff (5.6 kB) - added by limodou@gmail.com on 08/13/06 04:13:06.
Fix regular pattern [\w.]+ to [\w\.]+
template_02.diff (5.7 kB) - added by limodou on 08/14/06 20:06:59.
move rsplit to rindex and reduce duplicate path entry in path
template_03.diff (5.7 kB) - added by limodou on 08/14/06 20:51:08.
change rsplit to rindex. (upload again, last patch disappeared)
template_04.diff (5.5 kB) - added by racter on 09/14/07 15:46:50.
adjusted limodou's patch to apply to trunk as of 6213
patch_2539_code_tests.diff (17.4 kB) - added by durdinator on 10/21/07 16:34:47.
Patch against [6589], including tests and docs

Change History

08/13/06 03:08:37 changed by limodou

  • attachment template.diff added.

08/13/06 03:16:57 changed by limodou@gmail.com

  • summary changed from Can custom tag use namespace to [Patch]Custom tags and filters can be restricted by namespace.

This patch include three modified files. So you can load a custom taglib in two styles in template file:

{% load example %}
{% load testapp.example %}

Then you can use tags and filters through three styles, for example:

{% testtag %}    <---- current usage
{% example.testtag %}
{% testapp.example.testtag %}

and you can also apply this style to filter, for example:

{{ "string"|testfilter }}
{{ "string"|example.testfilter }}
{{ "string"|testapp.example.testfilter }}

08/13/06 03:36:48 changed by limodou@gmail.com

I forgot that you can also use:

{% load testapp1.example %}
{% load testapp2.example %}

So you will see you can load homonymy taglibs distinquished by app name with this patch. And if there are homonymy tags, and you didn't restrict them with namespace, the last one will be effective. But you can restrict them by namespace, just like:

{% testapp1.example.tag1 %}
{% testapp2.example.tag2 %}

So this time, each tag will be different.

08/13/06 03:48:18 changed by anonymous

line 507: (?P<filter_name>[\w.]+) should be (?P<filter_name>[\w\.]+) right? otherwise you'll include any character, not just dots.

08/13/06 04:06:48 changed by limodou

Right. I'll change it.

08/13/06 04:13:06 changed by limodou@gmail.com

  • attachment template_01.diff added.

Fix regular pattern [\w.]+ to [\w\.]+

08/13/06 04:14:57 changed by Tom Tobin <korpios@gmail.com>

That's no so, anonymous:

[] Used to indicate a set of characters. Characters can be listed individually, or a range of characters can be indicated by giving two characters and separating them by a "-". Special characters are not active inside sets.

(Emphasis mine; from http://docs.python.org/lib/re-syntax.html)

limodou, there's no need for that patch. :)

08/13/06 04:15:44 changed by Tom Tobin <korpios@gmail.com>

Err, I should say there's no need for that patched patch. :">

08/13/06 04:19:45 changed by limodou@gmail.com

I tried two pattern, both are right.

08/14/06 10:03:06 changed by mhf@hex.no

This patch depends on rsplit, a function not found in python2.3:

>>> "foo.bar.baz".rsplit('.')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'str' object has no attribute 'rsplit'

The guilty line is in templatetags/init.py, line 5:

        __path__.extend(__import__(a.rsplit('.', 1)[0], '', '', ['']).__path__)

I think this could be used instead:

        __path__.extend(__import__('.'.join(a.split('.')[:a.count('.') and -1 or None])), '', '', ['']).__path__)

08/14/06 20:06:59 changed by limodou

  • attachment template_02.diff added.

move rsplit to rindex and reduce duplicate path entry in path

08/14/06 20:51:08 changed by limodou

  • attachment template_03.diff added.

change rsplit to rindex. (upload again, last patch disappeared)

08/14/06 20:52:09 changed by limodou

Why my attachment can not be accepted? I upload it successful, but I cann't see them.

08/14/06 20:52:55 changed by limodou

My god, after submit last comment, I see them.

02/05/07 21:24:33 changed by anonymous

  • stage changed from Unreviewed to Design decision needed.

02/06/07 03:26:38 changed by Michael Radziej <mir@noris.de>

  • stage changed from Design decision needed to Unreviewed.

No anonymous stage changes, please.

02/16/07 04:01:36 changed by Simon G. <dev@simon.net.nz>

  • has_patch set to 1.
  • summary changed from [Patch]Custom tags and filters can be restricted by namespace to Custom tags and filters can be restricted by namespace.
  • needs_tests set to 1.
  • stage changed from Unreviewed to Design decision needed.

09/13/07 10:22:14 changed by adrian

  • stage changed from Design decision needed to Accepted.

Yes, yes, yes. This is a great suggestion.

09/14/07 12:22:23 changed by anonymous

  • owner changed from nobody to anonymous.
  • needs_better_patch set to 1.
  • status changed from new to assigned.
  • needs_docs set to 1.

patch no longer applies

09/14/07 12:22:41 changed by racter

  • owner changed from anonymous to racter.
  • status changed from assigned to new.

09/14/07 15:46:50 changed by racter

  • attachment template_04.diff added.

adjusted limodou's patch to apply to trunk as of 6213

09/14/07 16:00:11 changed by anonymous

  • needs_better_patch deleted.

09/14/07 17:50:13 changed by racter

  • owner changed from racter to anonymous.
  • needs_better_patch set to 1.
  • status changed from new to assigned.

actually my revision of that patch still has some problems - i'm writing tests now & will try to work it out.

09/17/07 05:03:48 changed by durdinator

  • cc set to me@andy.durdin.net.

This will need to play nicely with [6289] -- loading templatetags from subdirectories.

Due to that change, a conflict between app_name.tag_library and tag_library.subdirectory could arise:

foo/
    templatetags/
        bar.py

baz/
    templatetags/
        foo/
            bar.py

In such a case, the app_name.tag_library should take priority.

10/18/07 18:33:17 changed by durdinator

  • needs_better_patch deleted.
  • needs_tests deleted.

OK, this looks like it's stagnating, and it's something I definitely want. So here's a patch against [6507]. It's not based on limodou's or racter's work, and is more comprehensive in what it tidies up. Here's a summary of the result:

All tag libraries have an associated fully qualified name, which looks like "app_name.tag_library_name"; this fully qualified name can be used instead of the unqualified library_name in the {% load %} tag:

Normally we'd do
{% load humanize %}
But if another installed app has a 'humanize' tag libary, we might need to do
{% load django.contrib.humanize.humanize %}

If more than one installed app has a tag library with the same name, then the app closest to the start of the INSTALLED_APPS list will take precedence if the unqualified name is used.

Correspondingly, templatetags and filters are also namespaced -- by the name of the tag library as given to {% load %}. So you can do this:

{% load library %}
{% load otherapp.library %}

{% library.mytag %} # Outputs "A"
{% otherapp.library.mytag %} # Outputs "B"

But not this:

{% load firstapp.library %}
{% library.mytag %} # We've not loaded anything as 'library'

If there is a conflict in tag names, then the last loaded tag library takes precedence (the same as the behaviour in trunk in such a case).

All that applies to tags also applies to filters, of course.

The standard django tag libraries can be accessed via their fully qualified names "django.defaulttags", "django.defaultfilters", "django.loader_tags", and "django.i18n".

Possible backward-incompatible changes (not sure if any of these changed interfaces were intended to be publically used):

  • The items of django.template.libraries and django.template.builtins are now tuples, not Library instances.
  • Template.add_library and django.template.add_to_builtins require additional arguments.
  • The django.templatetags package no longer augments its path with from all installed apps' "templatetags" packages -- instead it is limited to the standard set of django tags.

A definite (though doubtless rare) backward-incompatible change:

  • {% load foo.bar %} will load from foo<app>.templatetags.bar in preference to <some_app>.templatetags.foo.bar.

Final notes:

The django and contrib tests that used template.libraries and/or add_to_builtins have been updated, so they should still pass (I've not checked the humanize or markup tests though).

The admin docs has been updated to list all tag libraries available, and list the fully qualified name alongside the unqualified name.

And I still need to modify the documentation to accommodate these changes, but I'll do that in another patch, because it's getting late.

10/21/07 16:34:15 changed by durdinator

Updated patch against [6589]; the docs for the "load" tag have been updated.

10/21/07 16:34:47 changed by durdinator

  • attachment patch_2539_code_tests.diff added.

Patch against [6589], including tests and docs


Add/Change #2539 (Custom tags and filters can be restricted by namespace)




Change Properties
Action