Use Django template syntax in a css file

后端 未结 3 419
旧巷少年郎
旧巷少年郎 2020-12-19 05:28

I have a css file home_global.css which has the following in it:

body {
    background-image: url(\"{% static \'citator/citator.jpg\' %}\");
}


        
相关标签:
3条回答
  • 2020-12-19 05:32

    As you correctly pointed out, Django templates can be used for any text file, not just HTML. However, you need to make sure they're rendered by the template engine, providing a specific url and a view.

    That way, you can expect to have all variables and tags interpolated, and in particular to have "static" replaced by settings.STATIC_URL. However, I wouldn't insist in prepending "/static/" to the url of the CSS file itself ... that would be cheating, as you're rather rendering the file dynamically.

    In practice:

    project/urls.py

    from django.urls import path
    from django.views.generic import TemplateView
    
    urlpatterns = [
        ...
        path('css/home_global.css', TemplateView.as_view(
            template_name='home_global.css',
            content_type='text/css')
        ),
        ...
    ]
    

    The view is rather trivial, and has been inlined in urls.py. Please note I also specified the appropriate mimetype 'text/css'.

    Here, I prepended a 'css/' prefix to the url, but this is not necessary, and you don't need a "css" folder in your project; just make sure that the template engine can find "home_global.css"; that is, put it in the /template/ subfolder of any installed app, or even in the project if it is listed among the installed apps:

    project/templates/home_global.css

    {% load static %}
    
    body {
        background-image: url("{% static 'citator/citator.jpg' %}");
    }
    

    You can check immediately the result by navigating to this url with your browser:

    http://127.0.0.1:8000/css/home_global.css
    

    which renders the document as follows:

    body {
        background-image: url("/static/citator/citator.jpg");
    }
    

    and include it in main template as required:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <link rel="stylesheet" href="/css/home_global.css" type="text/css">
        ...
    

    Should you need to render many css documents, it might be convenient to treat the filename as parameter, then use a single view for all documents. In this case I would opt for a function based view, for simplicity:

    urls.py:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        ...
        path('css/<str:filename>.css', views.css_renderer),
        ...
    ]
    

    where:

    views.py

    from django.shortcuts import render
    
    
    def css_renderer(request, filename):
        return render(request, filename + '.css', {}, content_type="text/css")
    

    and in your main template:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <link rel="stylesheet" href="/css/home_global.css" type="text/css">
        <link rel="stylesheet" href="/css/another.css" type="text/css">
        <link rel="stylesheet" href="/css/yet_another.css" type="text/css">
        ...
    
    0 讨论(0)
  • 2020-12-19 05:40

    Chopped off the particular part of the CSS tag and add into HTML file using style tag. A quick fix and worked for me.

    main.css

      ...
    
    #banner {
        background-color: #e5474b;
        color: #f2a3a5;
        padding: 13em 0 11em 0;
        background-color: #0c0c0c;
        background-image: url("/images/banner.jpg"); <-- Remove this part and put under html
        background-size: cover;
        background-repeat: no-repeat;
        background-position: 15% left;
        text-align: right;
        position: relative;
        z-index: 9999;
    }
      ...
    

    index.html

    <head>
      ...
      <style>
        #banner {
          background-image: url("{% static 'images/banner.jpg' %}");
        }
      </style>
     ...
    </head>
    
    0 讨论(0)
  • 2020-12-19 05:41

    Okay well after a month and a half I decided to just go through the docs and see whether I could figure this one out myself. And I have a working solution. Here's how to do it.

    STEP 1: add some directories and setup some new variables in settings.

    First, I assume that you already have a directory structure like this for static files:

    /<app_name>/static/<app_name>
    

    Add another sub-directory called "templates". This is where we will make our templates. This is not where they will be saved. So you should now have this:

    /<app_name>/static/<app_name>/templates
    

    In this directory, add your css template. Here's my example, saved as "test.css":

    {% load static %}
    body {
        background-image: url("{% static 'citator/citator.jpg %}");
    }
    

    Now add these variables to settings. Note, I only have one app. If you have more, find a more manageable way of doing this:

    APP_NAME = "<your app's name>"
    STATIC_TEMPLATE_PATH = os.path.join(BASE_DIR, APP_NAME, "static", APP_NAME, "templates")
    

    Next we need to write a custom command that will run the Django Template Engine on these templates. To do this, navigate to:

    /<app_name>/management/commands
    

    If you don't have these directories, make them.

    Then you need to make a file, call it something like "render_static_templates.py", with this in it, in this directory:

    from django.core.management.base import BaseCommand 
    from django.template import engines
    from <project_name>.settings import STATIC_TEMPLATE_PATH, APP_NAME
    import glob 
    import os
    
    def find_templates(stem: str):
        """
        Custom template finder that just looks in 
        your new static templates directories for templates
        """
        leaf = "*"
        path = os.path.join(stem, leaf)
        all_templates = glob.glob(path)
        return all_templates
    
    
    class Command(BaseCommand):
        def handle(self, *args, **options):
    
            # Get the file paths for all our new static templates:    
            all_templates = find_templates(STATIC_TEMPLATE_PATH)
    
            # See docs: https://docs.djangoproject.com/en/2.1/topics/templates/    
            django_engine = engines['django']
    
            for path in all_templates:
                template = django_engine.get_template(path)
                # Debug if you want. The URL should now be resolved in this print output.
                print(template.render())
    
                # Now we need to save the RENDERED template somewhere. I save it up one level from the templates folder, so that collectstatic can find it. You can put it elsewhere.
                leaf = path.split("/")[-1]
                save_path = os.path.join(APP_NAME, "static", APP_NAME, leaf)
                # Debug
                print(save_path)
    
                with open(save_path, "w") as f:
                    f.write(template.render())
    

    What you do next is run this new management command:

    python manage.py render_static_templates
    

    You should now be able to see the rendered template in

    /app/static/app
    

    Next run

    python manage.py collectstatic
    

    Assuming you have your STATIC_ROOT and STATIC_URL set up correctly, you will have the rendered template moved to where it should be. In my case:

    /static/<app_name>
    

    From there, the RENDERED template will be served using whatever you use to serve. (I use whitenoise). And if all has gone well, you should see a background image on your page!

    Possible improvements: - Better directory structures. - Integrating into the "collect_static" command.

    0 讨论(0)
提交回复
热议问题