How to Create Mobile-Friendly Web Applications using Django Framework – Part 3

“This article is revised and updated with latest version of Django – May 2016” In Part 1 of this series you learned how to install and configure Django in a virtual environment and you...

Spread the love

“This article is revised and updated with latest version of Django – May 2016”

In Part 1 of this series you learned how to install and configure Django in a virtual environment and you created the skeleton of your first project.

Then in Part 2 we created an application and a model for Post objects, which we later migrated to the database. Finally, we showed you how to integrate your newly created application to the Django administration user interface.

These articles are part of Django series:

Installing and Configuring Django Web Framework with Virtual Environments – Part 1

Reviewing Python Basics and Creating Your First Web Application with Django – Part 2

Creating Mobile Friendly Web Application with Django

Creating Mobile Friendly Web Application with Django – Part 3

In this final guide we will discuss how to access the application using the UI and how to make it mobile-friendly for all kind of devices. That said, let’s get started.

Creating objects via the Django admin interface


To create objects of type Post (remember that is the model we defined in Part 2 of this series), we will use the Django admin interface.

Make sure the Django built-in web server is running on port 8000 (or another one of your choosing) by running the following command from the outer myfirstdjangoproject directory:

# cd ~/myfirstdjangoenv/myfirstdjangoproject
# python manage.py runserver 0.0.0.0:8000

Now open your web browser and point to http://ip-address:8000/admin, then log on using the credentials you set up in the previous article and start writing a post (which, again, will create an object of type Post and insert the associated data into the underlying database):

Django Administration

Django Administration

Repeat the process 2 or 3 times:

Create Object in Django

Create Object in Django

After we have created a couple of posts, let’s see what we need to do in order to display them using our web browser.

Our initial view

Our first view (~/myfirstdjangoenv/myfirstdjangoproject/myblog/views.py) will be in charge of filtering all Post objects and returning those where the value of whenPublished is less than or equal to the current date and time (whenPublished__lte=timezone.now()) ordered by descending whenPublished, which is the same as saying “latest first“.

These objects are saved into a variable conveniently named posts, and are returned (identified as allposts) to be embedded in the HTML, as we will see in the next section:

from django.shortcuts import render
from .models import Post
from django.utils import timezone
def posts(request):
posts = Post.objects.filter(whenPublished__lte=timezone.now()).order_by('-whenPublished')
return render(request, 'myblog/posts.html', {'allposts': posts})

Finally, the double underscore in whenPublished__lte above is used to separate a database field (whenPublished) from a filter or an operation (lte = less than or equal).

Once we have defined our initial view, let’s work on the associated template.

Create Template for our first Project

Following the directives and paths given in the previous section, we will store our initial template inside myblog/templates/myblog. This means you will need to create a directory named templates and a subdirectory called myblog:

# cd ~/myfirstdjangoenv/myfirstdjangoproject/myblog
# mkdir -p templates/myblog

We will call the template posts.html and insert the following code in it. You will notice that we are adding online references to jQuery, Bootstrap, FontAwesome, and Google fonts.

In addition, we have enclosed Python code inside curly brackets inside the HTML. Please note that for every object of type Post we will show its title, its published date and author, and finally its text. Finally, in red you will see that we make a reference to the objects returned via myblog/views.py:

Ok, here’s the posts.html file:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link href='https://fonts.googleapis.com/css?family=Indie+Flower' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Pacifico' rel='stylesheet' type='text/css'>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" type='text/css'">
<script src="https://code.jquery.com/jquery-2.1.4.min.js">
</script>
<style>
.title {
font-family: 'Indie Flower', serif;
font-size: 30px;
color: #1E90FF;
}
h1 {
font-family: 'Pacifico', serif;
font-size: 45px;
color: #1E90FF;
}
</style>
</head>
<body>
<div class="container"><h1>My blog</h1><br>
{% for post in allposts %}
<div>
<div class="title">{{ post.title }}</div>
<strong>Published on {{ post.whenPublished }} by {{ post.author }}.</strong>
<p>{{ post.text|linebreaks }}</p>
</div>
{% endfor %}
</div>
</body>
</html>

In the above template, the linebreaks filter is used to replace line breaks in plain text with the corresponding HTML equivalent (<br /> or </p>) to format each post properly with paragraph separation.

Next, we need to set up a mapping between URLs in our application and the corresponding views that return the data. To do so, create a file named urls.py inside myblog with the following content:

from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.posts, name='posts'),
]

The r'^$' deserves a little more explanation. The leading r instructs Django to treat the string inside single quotes as a regular expression.

In particular, r'^$' represents an empty string so that when we point our browser to http://ip-address:8000 (and nothing else), the data returned by the variable posts inside views.py (refer to the previous section) will be presented in our home page:

Last, but not least, we will include the urls.py file of our blog application (~/myfirstdjangoenv/myfirstdjangoproject/myblog/urls.py) into the urls.py of our main project (~/myfirstdjangoenv/myfirstdjangoproject/myfirstdjangoproject/urls.py):

from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'', include('myblog.urls')),
]

Then let’s start the web server:

# cd ~/myfirstdjangoenv/myfirstdjangoproject
# python manage.py runserver 0.0.0.0:8000

We should now be able to see the lists of posts we created earlier:

Check My Django Web Project

Check My Django Web Project

Thanks to Bootstrap, you can still have an excellent visualization in a smaller device:

Mobile Responsive Look of My Project

Mobile Responsive Look of My Project

Summing Up

Let’s now review the concepts that we have covered in this article and throughout this series:

1. Each model defines an object and maps to a database table, whose fields in turn map to the properties of that object. On the other hand, a template defines the user interface where the data returned by the view will be displayed.

Let’s say we want to modify our model by adding a field named summary to the Post object, where we will store an optional brief description of each post. Let’s add the following line in myblog/models.py:

summary = models.CharField(max_length=350, blank=True, null=True)

As we learned in the previous article, we need to migrate the changes to the database:

# python manage.py makemigrations myblog
# python manage.py migrate myblog
Django: Migrate Changes to Database

Django: Migrate Changes to Database

Then use the admin interface to edit the posts and add a brief summary to each post. Finally, replace the following line in the template (posts.html):

<p>{{ post.text|linebreaks }}</p>

with

<p>{{ post.summary }}</p>

Refresh the home page to see the changes:

Django: Verify Changes to Web Project

Django: Verify Changes to Web Project

2. A view function takes a HTTP request and returns a HTTP response. In this article, def posts(request) in views.py makes a call to the underlying database to retrieve all posts. If we want to retrieve all posts with the word ansible in the title, we should replace.

posts = Post.objects.filter(whenPublished__lte=timezone.now()).order_by('-whenPublished')

with

posts = Post.objects.filter(title__icontains="ansible").order_by('-whenPublished')

By separating the user interface from the application logic in web applications, Django facilitates the tasks of maintaining and escalating apps.

3. If you followed the instructions provided in this series, the structure of your project should be as follows:

myfirstdjangoenv/myfirstdjangoproject
??? db.sqlite3
??? manage.py
??? myblog
? ??? admin.py
? ??? admin.pyc
? ??? __init__.py
? ??? __init__.pyc
? ??? migrations
? ? ??? 0001_initial.py
? ? ??? 0001_initial.pyc
? ? ??? __init__.py
? ? ??? __init__.pyc
? ??? models.py
? ??? models.pyc
? ??? templates
? ? ??? myblog
? ? ??? posts.html
? ??? tests.py
? ??? urls.py
? ??? urls.pyc
? ??? views.py
? ??? views.pyc
??? myfirstdjangoproject
??? __init__.py
??? __init__.pyc
??? settings.py
??? settings.pyc
??? urls.py
??? urls.pyc
??? wsgi.py
??? wsgi.pyc

In case the above list does not display correctly in your browser, here’s a screenshot of the output of the following command:

# tree myfirstdjangoenv/myfirstdjangoproject
My Django Protect Tree

My Django Protect Tree

Summary

Although all of these concepts may seem a little intimidating at first, I can assure you Django is well worth all the efforts necessary to become acquainted with it

I hope that the example that we have used in this series to introduce you to this outstanding web framework will motivate you to learn more. If so, the official Django documentation (which is constantly kept up to date) is the best place to start.

I can assure you that there is a whole lot more to Django than we can adequately cover in a series of articles, so feel free to explore it and learn by doing!

Feel free to drop us a note with questions or suggestions using the form below.

Facebook Comments
Spread the love

Posted by News Monkey