Override templatetags

1,188 views
Skip to first unread message

Lavric Traian

unread,
May 29, 2013, 3:25:29 PM5/29/13
to django...@googlegroups.com
Hi all,
I started playing around with django-oscar, I read the docs and I could customize models, views, etc.
My question is: how can I customize/override the templatetags of an application (e.g. catalogue)? Of course I tried to use the same logic as for customizing a view but it doesn't work.

Any ideas?
Thanks.

Shu Yang Quek

unread,
May 30, 2013, 5:30:38 AM5/30/13
to django...@googlegroups.com
Hi Lavric, 

It might not fit your use case exactly but I was wondering about how to deconflict templatetags and came across a solution. 

What exactly happened was I was looking to integrate easy_thumbnails for their smart cropping image fields. easy_thumbnails provides a "thumbnail" tag that conflicts with the similarly named templatetag of sorl-thumbnail's that oscar uses, subsequently screwing up all the templates it was used in.

My solution was to copy all templates that made use of the thumbnail templatetag and use django-smart-load-tag to specify the right version of the templatetag I was loading. I picked this up from this blog entry: http://timmyomahony.com/blog/2012/10/22/using-sorl-thumbnail-and-easy-thumbnails-same-template/

tl;dr

  • copy all templates that use the templatetag you wish to override into project template directory (i.e. override templates that contain the templatetags you wish to customize)
  • use django-smart-load-tag to specify which templatetag you would like to use exactly using the syntax {% load tag_name from module as tag_name %}

Lavric Traian

unread,
May 30, 2013, 7:20:20 AM5/30/13
to django...@googlegroups.com
Hi Shu Yang,

Thanks for the solution. I just tried it and it seems it works. One remark though: before using the {% load tag from module %} syntax, the smart_load tag of djngo-smart-load-tag has to be loaded in the template. Therefore I had to use something like:
{% load smart_load %}
{% load category_tags.category_tree from my_project.my_app%}

and of course I had to add 'smart_load_tag' to INSTALLED_APPS.
The thread is still open to other alternatives which doesn't require the installation of another app.

Thanks again.
Traian

David Winterbottom

unread,
May 30, 2013, 8:53:04 AM5/30/13
to django-oscar
Lavric, Shu,

The smart_load solution is interesting - I wasn't aware of that library.

Another approach is to provide your own template tags (which could subclass/extend the core ones) with a different name and override the relevant templates to use the new tags.  It's an invasive change though.

Further, the core template tags would be more customisable if their main logic was housed in a separate class which was loaded dynamically via get_class.  This would provide a mechanism for customising the core functionality.  


--
https://github.com/tangentlabs/django-oscar
---
You received this message because you are subscribed to the Google Groups "django-oscar" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-oscar...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-oscar?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
David Winterbottom
Head of Programming

Tangent Labs
84-86 Great Portland Street
London W1W 7NR
England, UK

Maik Hoepfel

unread,
Jun 6, 2013, 12:42:02 PM6/6/13
to django...@googlegroups.com, david.win...@tangentlabs.co.uk

Further, the core template tags would be more customisable if their main logic was housed in a separate class which was loaded dynamically via get_class.  This would provide a mechanism for customising the core functionality.  

That's true and definitely worth considering. Wouldn't fix the issues with the {% thumbnail %} tag as above though. Maybe one module oscar_tags that has imports for all tags we use, including wrappers around external tags like thumbnail?

Zachary Mott

unread,
Aug 27, 2015, 5:53:27 PM8/27/15
to django-oscar, david.win...@tangentlabs.co.uk, maik.h...@tangentlabs.co.uk
I realize I'm a little bit late to this party, but I'll contribute what I've learned for posterity's sake.

Once upon a time, I found that I needed to customize the category_tree templatetag.  As a big believer in the DRY approach to coding, I wanted to do this by copying as little core Oscar code as possible.  It turns out that this is doable, and only slightly less elegant that Oscar's approach to importing.  (Seriously, thanks to those guys, I think their get_model approach should be more widely adopted.)

As others have observed, Django looks through each of your INSTALLED_APPS in the order they're given to find a module that contains the specified template library.  (If you're curious, the source lives at  django.template.base.get_templatetags_modules.)  This means that you can define e.g. your_app.templatetags.category_tags, and if your_app is listed in INSTALLED_APPS before the call to oscar.get_core_apps, when you ask Django to {% load category_tags %}, Django will load your_app.templatetags.category_tags instead of oscar.templatetags.category_tags.

The next step is to customize the tag logic -- in my case, I needed to modify oscar.templatetags.category_tags.do_category_list so that it would hide certain categories based on which user was logged in.  I determined that oscar.templatetags.category_tags.CategoryTreeNode performed the actual task of retrieving a list of Categories, so I subclassed it in my_project.templatetags.category_tags.  After that, I had to register oscar.templatetags.category_tags.do_category_list as a tag in my_project.templatetags.category_tags so it would be available for use in my templates.

After I registered category_tree, my templates loaded the customized library and rendered the tag, but I wasn't seeing the changes I had made to CategoryTreeNode.  After a little bit of research I determined that this is due to the way Python handles variable scope.  The broadest scope a variable can achieve in Python is at the module level.  Even though I had declared my_project.templatetags.category_tags.CategoryTreeNode,  do_category_list was using oscar.templatetags.category_tags.CategoryTreeNode internally, because they were both part of the oscar.templatetags.category_tags module.  Once I overwrote Oscar's CategoryTreeNode with my custom CategoryTreeNode, everything was peachy.

Here's an abridged version of what my_app.templatetags.category_tags looked like when I was all finished:

from django import template
from oscar.templatetags import category_tags

register = template.Library()

# Customize Oscar's CategoryTreeNode
class CategoryTreeNode(category_tags.CategoryTreeNode):
    def render(self, context):
        """Do some custom stuff"""

# Overwrite Oscar's CategoryTreeNode with my own custom CategoryTreeNode
category_tags.CategoryTreeNode = CategoryTreeNode

# Register the actual template tag, reusing Oscar's logic.
register.tag(name="category_tree")(category_tags.do_category_list)

I hope someone somewhere finds all this useful.  It would be really great if it could be added to Oscar's documentation.

Ke T

unread,
Apr 15, 2022, 12:11:30 PM4/15/22
to django-oscar
Zachary, 

Really appreciate your detailed and thorough explanation -- 6.5 years later and it's still the most helpful instructions I was able to find.

This worked for me with one minor adjustment. In my case, I'd customized product_tags.py and then placed it within myproject.catalogue.templatetags, which is a forked Oscar app. And how I got this to work was by loading the forked Oscar app, myproject.catalogue.apps.CatalogueConfig, after all of Oscar's builtin apps.

So my INSTALLED_APPS looked something like this:

INSTALLED_APPS = [
      ...
      # oscar apps here
      'oscar.config.Shop',
      'oscar.apps.analytics.apps.AnalyticsConfig',
      ...
      # the app containing templatetags.product_tags.py
      'myproject.catalogue.apps.CatalogueConfig',
      ...
]


All things considered, this adjustment might be a product of my project's site structure, but I will leave this here incase it saves someone some troubleshooting.


Reply all
Reply to author
Forward
0 new messages