1

I am updating old django code from method-based views to class-based views.

I know how to include media (css/js) in forms via the Media class

How can I use the media class if my class based view does not contain any forms?

guettli
  • 25,042
  • 81
  • 346
  • 663
  • if the static files are not related to any forms, then just put them in the HTML template which your CBV is using – v1k45 Jan 11 '17 at 14:03
  • @v1k45 The template I have does not render a whole page. Just a snippet. AFAIK js-includes should be in the ``. I don't know how to put include a JS-file in my template, since I would like to have the include in the ``. – guettli Jan 11 '17 at 15:24
  • You can override/extend the code in the `head` tag by by extending the base template file and then adding the js file inside your head`{% block %}` . [see this](https://docs.djangoproject.com/en/1.10/howto/static-files/) – v1k45 Jan 11 '17 at 15:29
  • How exactly are your forms generated? – Udi Jan 11 '17 at 21:57
  • @Udi there are no forms in the view. I updated the wording, maybe it is more clear now (I am not a native speaker). – guettli Jan 16 '17 at 15:31
  • Please add your "old django code". – Udi Jan 16 '17 at 19:06

3 Answers3

6

CSS/JS are usually managed in the template itself and not in the view. See https://docs.djangoproject.com/en/1.10/howto/static-files/

For example, use base.html:

<!DOCTYPE html>
<html>
    <head>

        <title>
            {% block page_title %}{{ page_title }}{% endblock %}
        </title>

        {% block css %}
        {% endblock %}

    </head>
    <body>

        {% block main %}
        {% endblock %}

        {% block scripts %}
        {% endblock %}

    </body>
</html>

and extend it with my_page.html:

{% extends "base.html" %}
{% load staticfiles %}

{% block page_title %}
Hello!
{% endblock %}

{% block css %}
    <link href="{% static "page.css" %}" rel="stylesheet"/>
{% endblock %}

{% block main %}
Yo!
{% endblock %}

{% block scripts %}
    <script src="{% static 'my_scripts.js' %}"></script>
{% endblock %}
Udi
  • 29,222
  • 9
  • 96
  • 129
  • Can you please provide an example? The docs you mention show this `My image`. But how to do add CSS/JS at the top of the page (my template uses inheritance)? – guettli Jan 17 '17 at 14:19
  • thank you for the example. If I write a re-usable app. Can I be sure that the base template (which is not provided by the app, but by the project) always has the blocks `css` and `scripts`? – guettli Jan 18 '17 at 10:20
  • No, you can't. :-) – Udi Jan 18 '17 at 11:11
  • I think this is a major issue. Or I am missing something. – guettli Jan 18 '17 at 11:38
  • What's the issue? That users of your reusable app would have to follow some instructions about how to integrate it into their templates? This isn't uncommon at all, I don't see it as something you need to worry about. @udi's answer is solid. Again, these are perfectly reasonable things to ask of your potential end-users who might implement your reusable app. The only thing you would probably want to worry about is making sure to provide enough examples in the docs for the end-users. – YellowShark Jan 21 '17 at 07:50
  • See [django-bootstrap3](https://django-bootstrap3.readthedocs.io/en/latest/) or [django-leaflet](https://github.com/makinacorpus/django-leaflet) for examples of how to build reusable apps with client side/template rendering code. (Some options: template tags/filters, base templates) – Udi Jan 21 '17 at 17:36
  • I looked at leaflet https://github.com/makinacorpus/django-leaflet/blob/master/example/mushrooms/templates/index.html I see `leaflet_js`. How to get the `leaflet_js` into the base template of my project? Since the template blocks `css` and `scripts` are no django standard, I guess I have to modify the base template for the reusable app. That's not plug+play. – guettli Jan 25 '17 at 08:13
  • @YellowShark you said "What's the issue? That users of your reusable app would have to follow some instructions about how to integrate it into their templates? This isn't uncommon at all". Of course this is possible. But I think this wastes precious time. It would be much easier if it would just work without writing and reading instructions. In my case I had to use block `extrahead`. – guettli Oct 04 '19 at 12:54
3

Django Sekizai is meant for this:

Here is the example from their documentation:

{% load sekizai_tags %}

<html>
<head>
{% render_block "css" %}
</head>
<body>
Your content comes here.
Maybe you want to throw in some css:
{% addtoblock "css" %}
<link href="/media/css/stylesheet.css" media="screen" rel="stylesheet" type="text/css" />
{% endaddtoblock %}
Some more content here.
{% addtoblock "js" %}
<script type="text/javascript">
alert("Hello django-sekizai");
</script>
{% endaddtoblock %}
And even more content.
{% render_block "js" %}
</body>
</html>

This example shows everything in one template, but - of course - you can split that into multiple templates either by inheritance or includes and use the addtoblock directives in any of the partial templates.

A more complex, real life example is also in their documentation.

Risadinha
  • 16,058
  • 2
  • 88
  • 91
2

Here is a small mixin class that can help you add Media to views based on CreateView, UpdateView, and DeleteView:

class InjectFormMediaMixin(object):
    def get_form_class(self):
        form_class = super(InjectFormMediaMixin, self).get_form_class()
        if hasattr(self, 'Media') and not hasattr(form_class, 'Media'):
            form_class.Media = self.Media
        return form_class

Example:

class CreateFooView(InjectFormMediaMixin, CreateView):
    model = models.Foo
    fields = (
        'name',
    )

    class Media:
        css = {
            'all': ('pretty.css',)
        }
        js = ('animations.js', 'actions.js')
Udi
  • 29,222
  • 9
  • 96
  • 129
  • My view is not a subclass of `CreateView`. I guess `get_form_class()` does not get called. But I am unsure. – guettli Jan 11 '17 at 18:18
  • Please add your view class, or try to find where your form is created. – Udi Jan 11 '17 at 21:56
  • there is no form in my view. Take a look at the "about" example. AFAIK there is no form involved: https://docs.djangoproject.com/en/1.10/topics/class-based-views/#simple-usage-in-your-urlconf – guettli Jan 12 '17 at 10:12