Advertisement

A Django App - with Model Layer

Madanasekaran.P

For our app to interact with the database, we have to use a driver or connector of the language provided by the database vendor; but one has to use database specific “SQL” to interact with it. ORM is an abstraction over the connector. Though an ORM makes use of a connector it enables one to manipulate “objects” to accomplish the same tasks without having to write the required lines in specific SQL. It is the job of the ORM to translate the object-oriented syntax into a lower level SQL that can be executed by the connector.

Django: 

Django started as an internal project at the Lawrence Journal-World newspaper in 2003. The web development team there often had to implement new features or even entire applications within hours. Therefore, Django was created to meet the fast deadlines of journalism websites, whilst at the same time keeping the development process clean and maintainable. In short Django is a web framework in Python that comes with “batteries included”. One of the included batteries is the fully functioning ORM. Django has a built-in ORM and we do not require an external ORM library.ORM is a rich data access layer that bridges an underlying relational database with the object-oriented nature of the language used.Otherwise, there will be a paradigm mismatch between the objects that represent data in a OOPs language and the tables used to store that data in a relational database. When an ORM is used, the tool will take care of this mismatch and the programmer can simply design and code in terms of classes and objects, without bothering about the mismatch or the low level SQL required for interacting with the databases. A lot of discussions are going on in the programming community whether the overhead of ORM is required, as the db interfaces with “raw SQL queries ” execute generally faster than an ORM; but the programmer’s productivity gains through the use of ORMs is more than compensate for the slight fall in performance of the app .The ORMs have their own advantages like the use of OOP’s syntax in place of low level “SQL”, an abstraction that can be used with different relational databases in place of different SQL for different databases, use of features like data aggregation or calculated fields that need  not map to any column in the tables, protection against SQL injection attacks and so on.

Model Class :

A Model, primarily, is a class which has fields that will be mapped to a database table. It can have some custom methods also. Django’s ORM, by automatically attaching a “manager” to the Model class, provides to the model class methods to query the database. The manager by default is called “objects”. In other words; by extending models.Model, our class becomes a “specialized” class that will be taken care of by the ORM .It contains the essential fields and behaviors of the data we are storing and generally maps to a single database table. The default behaviour is that the table name is derived from the name of the application and the class, when migrated. The attributes become column names. An instance of the class becomes a record. A number of articles on ORMs especially Hibernate and ActiveRecord are available on the web site of DeveloperIQ. There are two ORM patterns 1) mapper 2) wrapper. In the wrapper pattern, followed by Django’s ORM/ActiveRecord, model object is just a wrapper around table and no separate mapping file is used. Each object is responsible for saving, updating and deleting itself in the database. A programmer can simply invoke the methods like save(),query() etc on the Class or object.

Django installation and project creation:

Execute
pip install django
This will install the recent version of Django.

Execute
pip install psycopg2
This will install the PostgreSQL  driver.

As in the earlier article, in the command prompt change to the directory of your choice and create a project executing

dango-admin startproject mysite

This creates the folder “mysite” which is the project root. Within this folder,   you can see the file  “manage.py” and another folder of the same name ie “mysite” containing a few configuration files, including “settings.py”, the main configuration file of the project  If you have a look at INSTALLED_APP in “settings.py”,  there, you can see that a number of applications are installed and services are provided when we start a project.  The “manage.py” is  a tool to create and manage our own application within this project and avail those services provided by Django. Change to mysite and execute  

python manage.py startapp weblog 

If you open the project folder-mysite- in an editor/IDE, PyCharm community edition is free for educational purposes and this is an excellent IDE for Python. You can see that the project contains the  created “weblog” directory which will be as under:

The “__init.py__” in “weblog” directory and “migrations” sub-directory are empty, but, as mentioned earlier, they enable Python to recognize the directories that contain them as Python packages. We will see other files in the course of this article. But bear in mind the following request -> response flow when you use any Python web Framework or for that matter H

  • TCP/IP is used to establish a connection between the client and the server.
  • HTTP is used for communication on that connection.
  • Server sends the request to an instance of web application we code and gets response from it. Ultimately the server sends the response adding some headers etc to the client. When we use Django or Flask “WSGI” protocol is used for communication between the server and our web app. In a Django App a view function is used to handle the request.

Administrative page:

One of the applications that is installed by default when we start a project 
is 'django.contrib.admin'.The generated file “admin.py” imports admin module from it as
shown below. The admin.py will read as under:

 

/weblog/admin.py

from django.contrib import admin
# Register your models here.

When we register our models here, in a single line of code, as shown below, we get an admin interface for adding or changing our model instances. We can complete the module as under:

 

/weblog/admin.py

from django.contrib import admin
from .models import BlogPost
# Register your models here.
admin.site.register(BlogPost)

Cofiguration file -app.py
This is the configuration file of the application. The generated file reads as under:

 

/weblog/app.py

from django.apps import AppConfig

class BlogConfig(AppConfig):
name = 'weblog'

You can see that the “BlogConfig” class has nothing but the name of the app. Later, we will be adding this name to the project configuration in “settings.py” for the project to manage our app.

 The Models

The file models.py will read as under:

 

/weblog/models.py
from django.db import models

# Create your models here.

 

 You can see that the module is empty, except importing “models” sub-package from the package “django.db”. The generated code can be filled up as under:

 

/weblog/models.py

from django.db import models
# Create your models here.
class BlogPost(models.Model):
title = models.CharField(max_length=150)
body = models.TextField()
timestamp = models.DateTimeField()

 BlogPost is not a normal Python Class. By extending Model class in the imported module “models”, it becomes a “special” class. The attributes /field types of BlogPost are not regular Python types. They are “types” defined in the imported “models” module, to enable mapping of attributes with fields in the table while migrating the inherited class.

Thus it gives Django ORM a lot of information. With it, the ORM  is able to:

  • Create a database schema (CREATE TABLE statements) for this app.
  • Create a Python database-access API for accessing BlogPost objects.(more about this when we see “view” code)
  • But first we need to tell our project that our “weblog” app is installed. We can do this by adding the name “weblog”, to the INSTALLED_APP in “settings.py” of the project.

Migrations folder

The folder “Migrations” is not a normal directory but a Python package as it contains __init.py__We can  generate a migration file any time after coding  the model class, as only a migration class is responsible for migrating a Model class as a table to a relational database. But as pointed out above, we have to check whether we have  added our app  in the INSTALLED_APP  in “settings.py”, the configuration file of the project. The “settings.py” should read as under:

 

Extract from mysite/settings.py

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'weblog',
]

 Now we can execute
python manage.py makemigrations weblog
Actually this will generate the file 0001_initial.py under migrations folder, from the code of our Model class. Though it is not necessary, you can go through the file to see the code that will be used when we actually execute “migrate” command. But all the apps specified in INSTALLED_APPS mentioned above will be migrated and it will be better if we use a production level database like PostgreSQL rather than Sqlite3.This requires some more modifications in “settings.py”

Other Changes required
ORM creates a table in the database specified in settings.py So Create a database “weblog”  in PostGreSQL using its “pgAdmin III” tool that comes bundled with PostGreSQL distribution. Then modify the database configuration in ‘settings.py’ as under

 


DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'weblog',  # put the database name
'USER': 'postgres',  # put your username
'PASSWORD': 'postgres',  # put your password
'HOST': 'localhost',  # specify the host
'PORT': '5432',  # specify the port
}
}


Views module

As mentioned in the earlier article, as against the controller actions in other MVC frameworks, in Django, only the view functions process incoming HTTPRequest and render HTTPReponse. We can code the index() function in the views module as under:

 

/weblog/views.py


from django.shortcuts import render
from weblog.models import BlogPost

def index(request):
posts = BlogPost.objects.all() # records fetched from db put in a variable
return render(request, 'weblog/index.html',{'posts': posts})  

  • A Manager is the interface through which database query operations are provided to Django models. But an instance of BlogPost can be saved in the DB by invoking save() method on the instance. Our code has no save(), as we will be using the built-in “admin” page for the purpose. To query the database, we are using the manager Django adds with the default-name “objects”  to every Django model class.

         In other words  Managers are the gateway to obtaining info from your database and by default they are called “objects” ; they have a number of  methods that enable you to  perform typical queries.

  • all:Return a QuerySet containing all the database records for the model in question.
  • filter: Return a QuerySet containing the model records matching specific criteria.
  • exclude:The inverse of filter—find records that don’t match the criteria.
  • get: Obtain a single record matching the given criteria (or raise an error if there are either no matches or more than one).

       All the above methods return a QuerySet. A QuerySet can be thought of as simply lists of model class instances (or database rows/records)

  • The render method takes three arguments: 1) request 2) template file which contains actual text of the response 3) context /dictionary that holds the Queryset variable/dynamic data. The template will use the context to evaluate the tags in it and provide dynamic information.

Templates The responsibility of a view function is to render a response. But the actual response to sent to the user is contained in a template. You can see one of the arguments to the function render() in view module is the template name. The render() also passes on to the template the “dynamic data” though a context/dictionary. When no template is used and the view function itself returns the HttpResponse,  it is said to  mix the business logic with the presentation logic. In applications with model layer the view function has to interact with a model, make some calculation etc . So by segregating of the presentation logic into a template, the code will become more maintainable. As we will see below, a template is a file that contains the text of a response, with placeholder variables for the dynamic parts which it will get through  context. The process that replaces the variables with actual values and returns a final response string is called rendering. As pointed out in the earlier article  we have to create a “templates” folder under our app “weblog”. Under “templates”  folder we create a sub-folder “weblog” to create namespace for our templates and avoid future confusion. We will also use a feature called template inheritance. The /weblog/base.html can read as under. It has nothing but some “css”  to be used by the pages in the site and a “block” for content. The templates that extend this base template should implement this content “block”.

 

/weblog/base.html

<html>
<style type="text/css">
body { color: #efd; background: #453; padding: 0 5em; margin: 0 }
h1 { padding: 2em 1em; background: #675 }
h2 { color: #bf8; border-top: 1px dotted #fff; margin-top: 2em }
p { margin: 1em 0 }  #-----1)
</style>
<body>
<h1>mysite.example.com</h1>
{% block content %}   #-----2)
{% endblock %}
</body>
</html>

  • Only css which can copied and pasted
  • the “content block” will be implemented by the template that extends this template.

The code for the “index.html” which extends the “base.html” is given below:

 

/weblog/index.html

{% extends "blog\base.html" %} #-----1)
{% block content %}  #-----2)     
{% for post in posts %} #----3)
<h2>{{ post.title }}</h2>
<p>{{ post.timestamp }}</p>
<p>{{ post.body }}</p>
{% endfor %}  #------3)
{% endblock %}  #------2)

  • Extends base.html
  • Contains the implementation for content block.

“for” action tag is used to iterate through the objects in the context/dictionary  passed on to it by the view.

URLs

The Django Project receives the HttpRequest for a Python page from the Web server, through WSGI. The deployed project should know to which view function it should forward the request for processing. The urlpatterns  serve the above purpose.ie  they map the request- url to the view function that processes it. The generated project directory contains a module /file “urls.py” for this purpose. The project’s configuration file “settings.py” points to this “ urls module”  as ROOT_URLconf.
The generated code will be as under

 

/mysite/urls.py

from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
url(r'^admin/', admin.site.urls),
]

You can see that contains necessary imports. The urlspatterns also contains a url that maps the request for admin .You can see that the request is forwarded to another/admin.site url for further processing. Regular expression has been used to define the url.Usually a regular expression starts with “^” and ends with “$”.Here no “$” is used only “/” is used in its place to show that the url is not complete(no view function is specified).The matching text will be chopped off and the remaining  string is sent to the included urls module for further processing. It is reiterated that only a trailing slash “/” is used to end the regular expression here as it is not the final URL, but only part of one. We can add a similar  url for our weblog app in the urlpatterns as under:
url(r'^weblog/', include('weblog.urls')), 

You can see that we are using explicitly the function include() , though the generated url for “admin” does not do so. The completed file may look as under

 

/mysite.urls.py

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^weblog/', include('weblog.urls')),  # code added now
]

To code the included “url” ,we can generate a New Python File under weblog and name it “urls.py”. It should read as under:

 

/weblog/urls.py

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

]

  The weblog URLconf simply maps the trimmed pattern received from the project URLconf. As mentioned above, the root URL trims the matched string and forwards the requesr-url for further processing in the included url. Here trimmed url is mapped  to the index() function in views module. Here  the  regular expression is ended with the symbol  “$” to show that it is a final url.

Preliminary steps required before running the app

You should migrate your applications-both built-in and the one you code before running your own app.

  • Execute Migrate 

Execute in the terminal of PyCharm IDE
E:\djanapp\mysite > python manage.py migrate
Now if you go to “pgAdmin III” and have a look at the tables generated, you can see a number of tables .Apart from the table weblog_blogpost for our app ‘weblog’,   ten other tables have been generated for the use of the applications specified in  INSTALLED_APPS  in “settings.py”.

  • create a superuser

A super-user is necessary to create users, add and edit records making use of “admin” page..
Execute in the terminal
E:\djanapp\mysite > python manage.py createsuperuser
The terminal will ask
Username:
Give some username(Remember it for logging in later)
You will be asked Email Address and Password and finally get the message “Superuser created successfully”.

Run the app

Now you may run the app by executing in the terminal
E:\djanapp\mysite > python manage.py runserver.
You can open a Browser and navigate to
Localhost:8000/admin.
You will see in the Browser the following

After logging in the browser will change as in Figure-5 as  under:

Click on Blog posts +Add. You will see figure-6 below:

You can add a record and click “Save and add another”. You can add a few more records before finally clicking “Save”. Now change the navigation address in the Browser to

localhost:8000/weblog

and may see something similar to the following Figure-7:

Conclusion:  

Django follows "batteries included" approach. The bootstrapping tools “django-admin” and “manage.py”  are similar to scaffolds in Rail. With them, when starting a project and an application within the project, we get a skeleton project and an app with a structure and some services; and the decision of technologies that will be used is also made for you. The project provides a number of services like admin, authentication, etc which your application can use.  Django has also built-in modules for templating, forms, routing, basic database administration, which your application can use. The number of services you get when you startproject with “django-admin” makes Django ideal for projects that will be maintained for some time. Bootstrapping tools gives you an easy way to get started even for small apps; but the negative side in using an “opinionated” framework is the lack of flexibility and we are provided with many services which we may not require or use.  But a free service like “admin.site”  is very handy to add, edit or delete your data into a relational database. We need not write any code for these functionalities. All that is expected from us is that we should register our model with “admin.site”  and this does not require more than a single line of code. Python programmers tend to build projects in Flask when they're reasonably self-contained and don't need an admin interface to update data. When one wants just a web- app wrapper for one’s data-science apps, Flask being a mini-framework appears to be given preference. But Django is preferable for those web projects that are going to be maintained over long periods of time and would take advantage of Django's admin interface and management commands. Its model layer/ORM has some advanced features like relationship and model inheritance and meta inner class. They say that the ActiveRecord pattern of Django ORM may become problematic, if your application becomes “complex”. But the admin interface may come in handy to handle those situations.

 








Added on August 12, 2017 Comment

Comments

#1

Ranga commented on August 15, 2017 at 5:23 p.m.

django-threadedcomments is a simple yet flexible threaded commenting system for Django.

#2

Angelo commented on August 16, 2017 at 9:47 p.m.

Can you post some of the articles on Splunk and slack. I am interested in learning these texhnology softwares.

#3

Anil Mishra commented on August 17, 2017 at 6:57 a.m.

Dear Sir. you are articles are really nice. I like reading your articles very much. Thanks.

#4

Madanasekaran commented on August 17, 2017 at 11:59 a.m.

Thanks

#5

Siddhesh Reddy commented on August 21, 2017 at 8:40 a.m.

Nice article. It helped me a lot.

Post a comment