Django is a "batteries-included" framework that comes with built-in scaffolding provided by the startproject command and the general concepts of apps. But, actually, Django provides incredible flexibility if desired around structure.
Consider how to architect a single page website: what's the simplest way to do it? Off the top of my head, at least 5 approaches come to mind. Because if you really think about it, apps are not mandatory at all but rather an organizational convenience that help reason about the codebase. Ditto for independent views files. We don't even need templates for a simple site when we can return strings in a view. Pretty much a urls.py file is the only "mandatory" part of the exercise.
Setup
On your command line, create a new directory called five and make a new Django project. We'll be using Pipenv here and calling our top-level directory config.
$ pipenv install django==3.0.7
$ pipenv shell
(five) $ django-admin startproject config .
(five) $ python manage.py migrate
(five) $ python manage.py runserver
Navigate over to the Django homepage at http://127.0.0.1:8000/ to confirm everything is working.
1. App + TemplateView
The "traditional" approach would be to create a dedicated app for static pages and use TemplateView, a generic class-based view provided by Django.
First, create the app which can be called whatever we choose. In this case, it'll be pages. Make sure you've stopped the local server by typing Control+c.
(five) $ python manage.py startapp pages
Add the new app to our INSTALLED_APPS setting.
# config/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'pages.apps.PagesConfig', # new
]
Update the config/urls.py file by importing include and adding a path for the pages app.
# config/urls.py
from django.contrib import admin
from django.urls import path, include # new
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('pages.urls')), # new
]
Ok, now what? We need a urls.py file within our app, a views file, and a template file.
Let's start with the pages/urls.py file. First, create it by using the touch command if you're on a Mac.
(five) $ touch pages/urls.py
The code includes a single path at home1/, a HomePageView we haven't created yet, and the URL name of home.
# pages/urls.py
from django.urls import path
from .views import HomePageView
urlpatterns = [
path('home1/', HomePageView.as_view(), name='home1'),
]
The view imports TemplateView and points to a template called home.html.
# pages/views.py
from django.views.generic import TemplateView
class HomePageView(TemplateView):
template_name = 'pages/home.html'
And finally we need a template. Create a templates directory within the pages app, then a new directory called pages, and finally the template called home.html.
<!- pages/templates/pages/home.html ->
<h1>Hello World</h1>
Start up the local server again with python manage.py runserver and navigate to http://127.0.0.1:8000/home1/.
This approach works well for large projects where you want a dedicated pages app for static pages. But since this article is for educational purposes, let's see 4 more ways we can achieve the same outcome.
2. Function-Based View
The first thing we could do is swap out the generic class-based TemplateView for a function-based view. Django allows for either using function-based or class-based views.
We'll import render at the top of pages/views.py and add a new view, home_page_view2, which requests the same template home.html.
# pages/views.py
from django.shortcuts import render # new
from django.views.generic import TemplateView
class HomePageView(TemplateView):
template_name = 'pages/home.html'
def home_page_view2(request): # new
return render(request, 'pages/home.html')
This new view will have its own path, home2/, in the pages/urls.py file.
# pages/urls.py
from django.urls import path
from .views import HomePageView, home_page_view2 # new
urlpatterns = [
path('home1/', HomePageView.as_view(), name='home1'),
path('home2/', home_page_view2, name='home2'), # new
]
Make sure the server is still running and navigate to http://127.0.0.1:8000/home2/ to see the new version of our homepage in action.
3. No Template!
A third approach would be to remove the template entirely, since all we're displaying is a short amount of text. We can create a new view that does this by importing HttpResponse and hard-coding the string Hello World to be returned.
# pages/views.py
from django.shortcuts import render, HttpResponse # new
from django.views.generic import TemplateView
class HomePageView(TemplateView):
template_name = 'pages/home.html'
def home_page_view2(request):
return render(request, 'pages/home.html')
def home_page_view3(request): # new
return HttpResponse('Hello World')
# pages/urls.py
from django.urls import path
from .views import HomePageView, home_page_view2, home_page_view3 # new
urlpatterns = [
path('home1/', HomePageView.as_view(), name='home1'),
path('home2/', home_page_view2, name='home2'),
path('home3/', home_page_view3, name='home3'), # new
]
Navigate to http://127.0.0.1:8000/home3/ in your web browser to see this third version in action.
4. No App!
We don't have to use apps, actually, if we don't want to. It's possible to create a "Hello World" page solely within our project-level config directory.
Here is all the code we need in just a single file:
# config/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView # new
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('pages.urls')),
path('home4/', TemplateView.as_view(template_name='pages/home.html'), name='home4'), # new
]
We've imported TemplateView at the top, create a new URL path, pointed to the existed template within the path, and provided an updated URL name of home4.
Navigate to http://127.0.0.1:8000/home4/ to see this in action!
5. Models
A fifth approach would be to use the database to display our "Hello World" message. That involves adding a models.py file and leveraging the built-in DetailView.
Create a new file called pages/models.py. We'll only add a single field, text, to the model called Post. Adding an optional __str__ method means the model will display nicely within the Django admin.
# pages/models.py
from django.db import models
class Post(models.Model):
text = models.TextField()
def __str__(self):
return self.text[:50]
Since we made a change to our database models, it's time for a migrations file and then to invoke migrate to update the database.
(five) $ python manage.py makemigrations
(five) $ python manage.py migrate
We'll want a basic pages/admin.py file to see our pages app within the admin so update pages/admin.py as follows:
# pages/admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
Create a superuser account and start up the server again.
(five) $ python manage.py createsuperuser
(five) $ python manage.py runserver
Log in to the admin at http://127.0.0.1:8000/admin/ and click on the link for Posts under Pages.
Click on "+Add" next to it. Add our text which will be "Hello World" and click the "Save" button in the bottom right.
Success! We've added our first post to the database.
To display this post we'll need a urls file, a views file, and a template file. Start with pages/urls.py where we'll import a new view called HomeDetailView and add a path for it.
# pages/urls.py
from django.urls import path
from .views import HomePageView, home_page_view2, home_page_view3, HomeDetailView # new
urlpatterns = [
path('home1/', HomePageView.as_view(), name='home1'),
path('home2/', home_page_view2, name='home2'),
path('home3/', home_page_view3, name='home3'),
path('home/<int:pk>/', HomeDetailView.as_view(), name='post_detail'), # new
]
The pages/views.py file needs to import DetailView at the top and our Post model. Then create HomeDetailView which references our Post model and a new pages/home5.html template.
# pages/views.py
from django.shortcuts import render, HttpResponse
from django.views.generic import TemplateView, DetailView # new
from .models import Post # new
class HomePageView(TemplateView):
template_name = 'pages/home.html'
def home_page_view2(request):
return render(request, 'pages/home.html')
def home_page_view3(request):
return HttpResponse('Hello, World!)
class HomeDetailView(DetailView): # new
model = Post
template_name = 'pages/home5.html'
The last step is to create a new template called home5.html that will display the text field from our model.
<!-- pages/templates/home5.html -->
{{ post.text }}
Make sure the local server is running python manage.py runserver and navigate to http://127.0.0.1:8000/home/1/ to see our 5th approach in action.
And there it is!
Conclusion
If you understand these five approaches you'll be well on your way to understanding all that Django has to offer. And you can start exploring additional ways to tackle this arbitrary challenge, for example, taking a look at base view class, get_context_data, HTTPRequest and likely many others.









Top comments (0)