Autodiscover widgets for Django applications registered in settins.py

The name may be a little confusing, but I don't know what else to call it.

I would like to create a Django project with a large set of applications that you could optionally turn on or off using the INSTALLED_APPS parameter in settings.py (you obviously also need to edit urls.py and run syncdb ). After you turn on the application should be able to automatically:

  • Register it in the search results for the entire site. Fortunately, django-haystack has this built-in module, so this is not a problem.

  • Register cron jobs. django-cron does just that. Not a problem.

  • Register the widget to be displayed on the main page. The home page should include a list of boxes with widgets from different applications.

    I was thinking about inclusion tags because you can put them anywhere on the page and they control both the content and the presentation. The problem is that I don’t know how to automatically get the list of inclusion tags provided by my applications and display them one by one on the main page. I need to somehow register them and then display all the registered tags.

+4
source share
4 answers

I'm not sure that using the inclusion tag is actually your best bet ... There is no easy way, AFAIK, to dynamically invoke template tags from a template (and this is not the point of the template anyway :-)

I believe that I can make the following assumptions about your widgets, correct me if I am wrong:

  • widget visualization function does not need parameters from the template context
  • at best, he will need the current request object (so that he can access user , session , etc.)

With this, you can think of your widgets as mini-views, returning a string instead of an answer:

 def my_widget(request): ... # Here too, the function control both presentation and content return render_to_string('my_widget.html', {'foo': bar}) 

Now there are two questions for the address:

  • How to get a dynamic list of all widget functions for all installed applications available in the template?
  • How to call these widget functions in a template?

First point :

An easy way is to rely on an agreement. They have a uniform list of functions in the template_widgets.py module in all your applications, for example:

 ## myapp/template_widgets.py def shopping_cart(request): # do something with the session/user ... return render_to_string('myapp/widgets/cart.html', {'cart': cart}) # Another widget func, not defined here from myapp.views import another_widget_func # The list of widget functions declared by this app widgets = (shopping_cart, another_widget_func,) 

Then you can download the global list of widgets by looking at INSTALLED_APPS and automatically get it in all of your templates (using the context processor ). Of course, it’s better to load this list lazily so as not to waste processor cycles creating it if you are not going to use it.

 ## myproject/context_processors.py from django.utils.importlib import import_module from django.utils.functional import lazy def widgets(request): def get_all_widgets(request): from django.conf import settings widgets_list = [] for app in settings.INSTALLED_APPS: try: mod = import_module(app+'.template_widgets') widgets_list.extend(mod.widgets) except ImportError: pass except AttributeError: # Couldn't find a widgets variable in app.template_widgets module, # probably better to raise a custom exception raise return widgets_list return {'widgets': lazy(get_all_widgets, list)(request)} 

Second point :

You now have a list of available widgets and are lazily loaded in each template. A convenient syntax for using it would be something like this:

 ## home.html ... <div id="widgets"> {% for widget in widgets %} <div class="widget"> {{ widget }} </div> {% endfor %} </div> 

But this will not work, {[widget}} here called, which needs the request parameter. Djano does not allow you to make calls with parameters from the template, so you need to slightly change the context processor to return a list of (lazily) evaluated widget functions.

 ## myproject/context_processors.py ... # replace `return widgets_list` with the following return map(lambda w: lazy(w, str)(request), widgets_list) ... 

And now, the above template code should work.

Notes

  • The order of the widgets in the list depends on the application orders in the INSTALLED_APPS and in each widgets list. It’s up to you to choose the right ordering method for you (for example, by weighing, using dict to access widget functions by name, etc.).
  • Remember to load the context processor and always use RequestContext .
+5
source

in your __init__.py application you can use the following lines:

 from django.template import add_to_builtins add_to_builtins('python.path.to.mytags') 

Thus, when the application module is imported, the tag library is loaded into the "built-in" tags, which are available everywhere without {% load%}

0
source

Do you know about Django-block ?

0
source

I would write a template tag that would populate a list of inclusion tags in a variable. Request django.template.Library register for them.

0
source

Source: https://habr.com/ru/post/1306113/


All Articles