51

I have my index.html in /static/ folder. My django app is running ok when i try:

http://127.0.0.1:8000/index.html

But i want to acces index.html by url:

http://127.0.0.1:8000/

I wrote a view and it works:

class IndexView(TemplateView):
    template_name = 'index.html'

I also added to urls.py(this lets me serve static like http://127.0.0.1:8000/css/style.css):

url(r'^(?P<path>.*)$', 'django.contrib.staticfiles.views.serve', {
            'document_root': settings.STATIC_ROOT, 'show_indexes':True
        }),

But i think there is a way to do what i want without TemplateView.

Any suggestions? Thanks. My django version is: Django 1.5

EDIT:

The reason i placed index.html into static: i want to make Phonegap compatible django app, so after proper coding, all i have to do is --> make .zip from static folder and upload it to Phonegap as mobile app. Easy and clean.

Feanor
  • 3,568
  • 5
  • 29
  • 49

5 Answers5

56

You can serve static/index.html for development like this:

if settings.DEBUG:
    urlpatterns += url(
        r'^$', 'django.contrib.staticfiles.views.serve', kwargs={
            'path': 'index.html', 'document_root': settings.STATIC_ROOT}),

But for production you should configure your nginx (or other frontend server) to serve index.html file for / location

UPDATE

I want to explain the case you should do like this. For example your django app is only admin and api view, but client interacts with a single page app (Ember, Angular, whatever). So you project has at least two subprojects, one with your main django app and the second is a client app with all html/js/css stuff. It is very convenient to have client scripts separate from django backend, it allows your frontend developers to do their job and avoid django existence (someday it can be moved to the distinct repo).

So in this case you get the following build workflow:

  1. Run client app sources watcher to rebuild your scripts/styles/templates (brunch watch, grunt job or gulp watch task)
  2. Collect static with django for production
  3. Make sure you have urlpatterns fix for developments and right nginx config for production

Here is my urls.py example

urlpatterns += patterns(
    'django.contrib.staticfiles.views',
    url(r'^(?:index.html)?$', 'serve', kwargs={'path': 'index.html'}),
    url(r'^(?P<path>(?:js|css|img)/.*)$', 'serve'),
)
Anton Egorov
  • 1,174
  • 1
  • 11
  • 21
  • 1
    Thanks for this. How do you deal with HTML5 History API and serving from a src folder? I build my Angular apps so that they are served from src during dev. I amended the patterns so that the index.html is caught by a catch all URL pattern and placed this before the pattern for assets. Seems to work. But I'd like to serve js/css/img from templates/src. Tried changing the doc. root but it doesn't work (can't paste code into replies argh) – Howie Nov 17 '14 at 13:53
  • 1
    @Howie is it open source project? Could you show me what you have? – Anton Egorov Nov 17 '14 at 20:31
  • 1
    Hi @Anton. Sorry for late response. I've created a boilerplate on Github to use your recommendation above. Perhaps you could provide a hint? The SPA works outside of Django, but is not served through Django https://github.com/howieweiner/django-angular-boilerplate. Thnx – Howie Nov 26 '14 at 17:38
  • 1
    From the Django docs Warning This view will only work if DEBUG is True. That's because this view is grossly inefficient and probably insecure. This is only intended for local development, and should never be used in production. – Martin Mar 12 '15 at 18:36
45

You don't need to subclass TemplateView in this case. You can use TemplateView directly in your url conf, as long as index.html is in your templates directory.

from django.views.generic.base import TemplateView

urlpatterns = [
    url(r'^$', TemplateView.as_view(template_name='index.html'), name="home"),
]
Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • So there is no way to serve static HTML file without passing it through template renderer? – Alex K Aug 13 '13 at 12:44
  • 5
    The [`views.serve`](https://docs.djangoproject.com/en/1.6/ref/contrib/staticfiles/#django.contrib.staticfiles.views.serve) helper is intended for development only. You shouldn't use Django for serving static files in production. Use your web server e.g. Apache or Nginx to serve static files. – Alasdair Aug 13 '13 at 13:04
  • 11
    @Alasdair Could you explain why not? I mean everybody says this, but they never say why. If you're serving an SPA that ships its entire view apparatus in one pre-compiled payload, it doesn't seem so bad to just let Django serve it up. Any given visitor only loads it one time. But if there are reasons that don't predate modern SPA architecture, I'd be very interested to know what they are. – npskirk May 22 '14 at 20:20
  • @npskirk because it incurs a CPU cost that is more significant that simply using Nginx. – airtonix Jun 21 '14 at 04:28
  • 2
    @npskirk The main reason not to use it in production is security, not efficiency. The [warning in the Django docs](https://docs.djangoproject.com/en/1.8/ref/contrib/staticfiles/#static-file-development-view) is pretty explicit. – Alasdair Jan 23 '15 at 10:27
  • 7
    don't forget to add `from django.views.generic import TemplateView` – Connor Leech May 11 '15 at 22:04
  • Isn't another reason for serving static file using the web server directly that it allows the client to cache those resources? – Feuermurmel Mar 09 '16 at 10:05
  • 2
    @Feuermurmel the client can cache a resource if the correct cache headers are set. It doesn't matter whether the page is served by Django or another web server. – Alasdair Mar 09 '16 at 10:09
  • @Alasdair You are right. But by default web servers will set those headers while web application frameworks won't (because they are designed for dynamic content). – Feuermurmel Mar 09 '16 at 10:59
  • @Feuermurmel I don't think that web servers will set those headers by default - it's not a safe assumption that index.html isn't going to change, just because it's a file on disk. In any case, I think we're going off topic here. – Alasdair Mar 09 '16 at 11:09
4

Check out my long explanation of how to serve index.html on / in this answer (or extended as a blog post). That solution alone might not be sufficient, however, if you want to have a full-fledged SPA served by Django (because you need frontend routing).

I've been playing with different methods for routing /static/ to /, forwarding all requests to the frontend, finding index.html files. In the end I found the best method to solve all of this was not by tweaking urls.py, but as an extension of WhiteNoise that I released as django-spa (installation instructions in the README).

You can find some of the related discussion in this WhiteNoise issue.

Community
  • 1
  • 1
metakermit
  • 21,267
  • 15
  • 86
  • 95
4

Just wrap your static HTML file in an iframe defined in a templated HTML file. With some style tweaks can make the iframe 100% width and height.

{% load static %}
<html>
    <head>
        <title>Templated HTML</title>

        <style>
            html, body {
                width: 100%;
                width: 100%;
                margin: 0;
                padding: 0;
                border-width: 0;
            }

            iframe {
                position: absolute;
                top: 0;
                left: 0;
                width: 100vw;
                height: 100vh;
                margin: 0;
                padding: 0;
                border-width: 0;
            }
        </style>
    </head>
    <body>
        {{ content }}
        <iframe src="{% static 'main/html/test.html' %}"></iframe>
    </body>
</html>
Geordie
  • 1,920
  • 2
  • 24
  • 34
  • Hi let say array name graph=['A.html','B.html'] then {% for i in graph %} {% endfor %} Any ideas to edit the src links, when i run it return **A server error occurred. Please contact the administrator.** – Shi Jie Tio Mar 25 '19 at 08:53
3

you can create templates directory, put the html there and then render it from views.py

    def index(request):
        return render(request, 'my_app/index.html', context={})

dont forget to set the templates_dir in the settings.py

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TEMPLATES_DIR = os.path.join(BASE_DIR, "templates")

TEMPLATES = [
{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [TEMPLATES_DIR,],
    'APP_DIRS': True,
    ...