Calling one python script from another

Ideally should should import requited python file using import into another and call required function from other programs but there could be some instances where you would need to trigger one python script from another.

This  is fairly simple.

Lets say I have following two program located in same folder and Let us try calling from is fairly simple

import os

os.system('python3.6 ' + '')

This code will trigger

Passing parameters to calling file

This needs minor changes. Whatever you need to pass, just mention that value or variable after a space.

import os

os.system('python3.6 ' + ' 11 ')

import sys
print("---This is inside script 2")

input_value = int(sys.argv[1])
print(" 0 ", sys.argv[0], )
print(" 1 ", sys.argv[1], type(sys.argv[0]))

Please note, 0th parameter is always the script name, you can pass multiple parameters.

Also, received files are always string, you need to change to required datatype using datatype conversion operators e.g. int(sys.argv[1])

Trigger file located at different directory

import os

file_path = '/home/user/code/quant/source/library/'
os.system('python3.6 ' + file_path + ' 11 22')

Please note the training '/' in file_path

How to insert data from pandas to PostgreSQL

When we have done our data analysis using pandas and now need to store this analysis, we can use to_csv option. However if data is too big, it make sense to store this in database.
Let us have a look at two simple methods to store data into PostgreSQL database.

Using sqlalchemy


import pandas as pd
from sqlalchemy import create_engine

df =pd.read_csv('input_file.csv',parse_dates=['timestamp'],index_col=0)

engine = create_engine('postgresql://admin:admin@localhost:5432/ibnse')
df.to_sql('stk_1min1', engine,if_exists='append')

Using psycopg2


pandas as pd
import psycopg2
conn = psycopg2.connect(database='dbname', user="user", password="password", host="", port="5432")
cur = conn.cursor()

df =pd.read_csv('input_file.csv',parse_dates=['timestamp'],index_col=0)
for index, row in df.iterrows():
    insertdata =  "('"+str(index)+ "','"+row[0]+"','"+str(row[1])+"','"+str(row[2])+"','"+str(row[3])+"','"+str(row[4])+"','"+str(row[5])+"','"+str(row[6])+"','"+str(row[7])+"','"+str(row[8])+"')"
    print("insertdata :",insertdata)

        cur.execute("INSERT INTO stk_1min1 values "+insertdata)
        print( "row inserted:", insertdata)
    except psycopg2.IntegrityError:
        print( "Row already exist ")
    except Exception as e:
        print( "some insert error:", e, "ins: ", insertdata)

Few points while using sqlalchemy

  • If table does not exists, it will get created.
  • If table exists and you want to append, you need to use if_exists='append',  Its wise choice to use this option in most of the cases.
  • When you use sqlalchemy, whole pandas dataframe will not be inserted even if you get unique index error for one single record.

How to read data from PostgreSQL to Pandas DataFrame

Usually for training and testing, we create pandas DataFrame from csv file but when we are working while large dataset or working with database stored in database, we need a way to fetch data into pandas DataFrame directly from database. In this article we will have a look at two methods for doing it.

Using sqlalchemy


import pandas as pd
from sqlalchemy import create_engine
engine = create_engine('postgresql://user:password@localhost:5432/dbName')

df = pd.read_sql_query("SELECT * FROM public.stk_1min1 where symbol = 'TCS'",con=engine)


You can write query before using pd.read_sql_query function

import pandas as pd
from sqlalchemy import create_engine
engine = create_engine('postgresql://user:password@localhost:5432/dbName')

stk = 'TCS'
query = "SELECT * FROM public.stk_1min1 where symbol = "+"'"+stk+"'"

df = pd.read_sql_query(query,con=engine)

Using psycopg2


import pandas as pd
import psycopg2
conn = psycopg2.connect(database='dbname', user="user", password="password", host="", port="5432")

df = pd.read_sql_query("SELECT * FROM public.stk_1min1 where symbol = 'TCS'",con=conn,index_col=['index'])


Similar to sqlalchemy example, you can write query before using read_sql_query function.

Getting started with Interactive Brokers Python API on Ubuntu

Interactive brokers offer one of the lost latest Trading desktop application and best part is that it offers API access to most of the worlds leading stock exchanges. For India, Interactive brokers provide free access to NSE data (monthly account maintenance charges of INR 200) which is nothing if you compare pricing by main competitor zerodha ( Streaming INR 2000 + Historic INR 2000).

In this article, let us have a look at how to get started with Interactive Brokers API access.

Step#1  Open an account

First and foremost, you need to have funded account with Interactive Brokers. They are opening account virtually provided you have all relevant documents scanned copy.

If you need an access to market data you need to keep $500 or its equivalent in your account.  in INR, you can transfer ~40,000/- to be on safer side.

Step#2 Activate Market data.

Its takes about a week for your documents to be verified and account activation. Once your account is activated, you need to suscribe to market data using following path.

Login to web portal –> User Settings –> Market Data Suscription (Click on gear sign>–> select required exchanges and market data type–> confirm.

And you are all set.

Please note for NSE, Equity and Futures and Options market data is separate, so you need to sele

Step#3 Download TWS

You can download TWS (Traders Workstation) from here. This is one of the most advanced if you compare it with other competitors.

You might ask, I need API access, why do I need TWS ? Well, Interactive Brokers API need TWS to be installed on local machine. In a way, API piggy backs on the TWS. More on this later

Step#4 Download API Libraries

You can download API libraries from here. You can choose stable version.

Step#5 Basic Setup

Let us downloaded version is “”. This might be different for you based on latest version released by IBKR

$cd ~/Downloads
$sudo unzip -d $HOME/
$cd ~/IBJts
~/IBJts$ls -la
~/IBJts$ ls -la
total 68
drwxr-xr-x  5 userid root            4096 May 29 09:39 .
drwxr-xr-x 36 userid userid  4096 May 29 11:16 ..
-rw-r--r--  1 userid root              21 Feb  6 01:04 API_VersionNum.txt
drwxr-xr-x  2 userid userid  4096 May 28 22:38 log
drwxr-xr-x  5 userid root            4096 Feb  6 01:07 samples
drwxr-xr-x  5 userid root            4096 Feb  6 01:07 source

You can find code inside source and sample folder.

Step#6  Configure TWS

As mentioned in step#3, you need TWS. You need to enable API access in TWS by making following changes.

Go to Edit -> Global Configuration -> API -> Settings and make sure the “Enable ActiveX and Socket Clients” option is activated as shown below:

Live Account 7496
Paper Trading 7497

Step#7 Sample Code

Go to source–>pythonclient–>tests

Here you will find many sample code for various tasks

Important note:

Whenever you run API, you need to make sure TWS is running. else you will get error like below

~/IBJts$ /usr/bin/python3 "/home/conquistadorjd/IBJts/source/pythonclient/working/check_connection v"
ERROR -1 502 Couldn't connect to TWS. Confirm that "Enable ActiveX and Socket EClients" 
is enabled and connection port is the same as "Socket Port" on the 
TWS "Edit->Global Configuration...->API->Settings" menu. Live Trading ports: 
TWS: 7496; IB Gateway: 4001. Simulated Trading ports for new installations 
of version 954.1 or newer:  TWS: 7497; IB Gateway: 4002

Step#8 Sample code for you first program

from ibapi.client import EClient
from ibapi.wrapper import EWrapper  

class IBapi(EWrapper, EClient):
     def __init__(self):
         EClient.__init__(self, self) 

app = IBapi()
app.connect('', 7496, 1)

#Uncomment this section if unable to connect
#and to prevent errors on a reconnect
import time


How to install jupyter notebook Ubuntu

similar to any other package, before installing anything on Ubuntu run following command

$sudo apt-get update

Once system is updated to latest packages, you can install jupyter using following command

$sudo python3.6 -m pip install jupyter
WARNING: The directory '/home/username/.cache/pip' or its parent directory is not owned or is not writable by the current user. The cache has been disabled. Check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Collecting jupyter
Downloading jupyter-1.0.0-py2.py3-none-any.whl (2.7 kB)
Collecting notebook
Downloading notebook-6.0.3-py3-none-any.whl (9.7 MB)
|████████████████████████████████| 9.7 MB 76 kB/s 
Collecting ipywidgets
Downloading ipywidgets-7.5.1-py2.py3-none-any.whl (121 kB)
|████████████████████████████████| 121 kB 294 kB/s 
Collecting nbconvert
Downloading nbconvert-5.6.1-py2.py3-none-any.whl (455 kB)
|████████████████████████████████| 455 kB 192 kB/s 
Collecting ipykernel
Downloading ipykernel-5.2.1-py3-none-any.whl (118 kB)
|████████████████████████████████| 118 kB 75 kB/s 
Collecting qtconsole
Downloading qtconsole-4.7.3-py2.py3-none-any.whl (117 kB)
|████████████████████████████████| 117 kB 126 kB/s 
Collecting jupyter-console
Downloading jupyter_console-6.1.0-py2.py3-none-any.whl (21 kB)
Collecting terminado>=0.8.1
Downloading terminado-0.8.3-py2.py3-none-any.whl (33 kB)
Collecting jupyter-client>=5.3.4
Downloading jupyter_client-6.1.3-py3-none-any.whl (106 kB)
|████████████████████████████████| 106 kB 139 kB/s 
Collecting Send2Trash
Downloading Send2Trash-1.5.0-py3-none-any.whl (12 kB)
Collecting ipython-genutils
Downloading ipython_genutils-0.2.0-py2.py3-none-any.whl (26 kB)
Collecting jinja2
Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB)
|████████████████████████████████| 125 kB 263 kB/s 
Collecting nbformat
Downloading nbformat-5.0.6-py3-none-any.whl (170 kB)
|████████████████████████████████| 170 kB 382 kB/s 
Collecting prometheus-client
Downloading prometheus_client-0.7.1.tar.gz (38 kB)
Collecting tornado>=5.0
Downloading tornado-6.0.4.tar.gz (496 kB)
|████████████████████████████████| 496 kB 99 kB/s 
Collecting traitlets>=4.2.1
Downloading traitlets-4.3.3-py2.py3-none-any.whl (75 kB)
|████████████████████████████████| 75 kB 82 kB/s 
Collecting pyzmq>=17
Downloading pyzmq-19.0.0-cp36-cp36m-manylinux1_x86_64.whl (1.1 MB)
|████████████████████████████████| 1.1 MB 71 kB/s 
Collecting jupyter-core>=4.6.1
Downloading jupyter_core-4.6.3-py2.py3-none-any.whl (83 kB)
|████████████████████████████████| 83 kB 212 kB/s 
Collecting widgetsnbextension~=3.5.0
Downloading widgetsnbextension-3.5.1-py2.py3-none-any.whl (2.2 MB)
|████████████████████████████████| 2.2 MB 178 kB/s 
Collecting ipython>=4.0.0; python_version >= "3.3"
Downloading ipython-7.13.0-py3-none-any.whl (780 kB)
|████████████████████████████████| 780 kB 203 kB/s 
Collecting bleach
Downloading bleach-3.1.5-py2.py3-none-any.whl (151 kB)
|████████████████████████████████| 151 kB 290 kB/s 
Collecting pygments
Downloading Pygments-2.6.1-py3-none-any.whl (914 kB)
|████████████████████████████████| 914 kB 130 kB/s 
Collecting mistune<2,>=0.8.1
Downloading mistune-0.8.4-py2.py3-none-any.whl (16 kB)
Collecting pandocfilters>=1.4.1
Downloading pandocfilters-1.4.2.tar.gz (14 kB)
Collecting testpath
Downloading testpath-0.4.4-py2.py3-none-any.whl (163 kB)
|████████████████████████████████| 163 kB 239 kB/s 
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='', port=443): Read timed out. (read timeout=15)",)': /simple/defusedxml/
Collecting defusedxml
Downloading defusedxml-0.6.0-py2.py3-none-any.whl (23 kB)
Collecting entrypoints>=0.2.2
Downloading entrypoints-0.3-py2.py3-none-any.whl (11 kB)
Collecting qtpy
Downloading QtPy-1.9.0-py2.py3-none-any.whl (54 kB)
|████████████████████████████████| 54 kB 36 kB/s 
Collecting prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0
Downloading prompt_toolkit-3.0.5-py3-none-any.whl (351 kB)
|████████████████████████████████| 351 kB 62 kB/s 
Collecting ptyprocess; os_name != "nt"
Downloading ptyprocess-0.6.0-py2.py3-none-any.whl (39 kB)
Requirement already satisfied: python-dateutil>=2.1 in /home/username/.local/lib/python3.6/site-packages (from jupyter-client>=5.3.4->notebook->jupyter) (2.8.1)
Requirement already satisfied: MarkupSafe>=0.23 in /usr/lib/python3/dist-packages (from jinja2->notebook->jupyter) (1.0)
Collecting jsonschema!=2.5.0,>=2.4
Downloading jsonschema-3.2.0-py2.py3-none-any.whl (56 kB)
|████████████████████████████████| 56 kB 106 kB/s 
Requirement already satisfied: six in /home/username/.local/lib/python3.6/site-packages (from traitlets>=4.2.1->notebook->jupyter) (1.14.0)
Collecting decorator
Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
Requirement already satisfied: pexpect; sys_platform != "win32" in /usr/lib/python3/dist-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets->jupyter) (4.2.1)
Collecting pickleshare
Downloading pickleshare-0.7.5-py2.py3-none-any.whl (6.9 kB)
Requirement already satisfied: setuptools>=18.5 in /home/username/.local/lib/python3.6/site-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets->jupyter) (45.1.0)
Collecting jedi>=0.10
Downloading jedi-0.17.0-py2.py3-none-any.whl (1.1 MB)
|████████████████████████████████| 1.1 MB 98 kB/s 
Collecting backcall
Downloading backcall-0.1.0.tar.gz (9.7 kB)
Collecting packaging
Downloading packaging-20.3-py2.py3-none-any.whl (37 kB)
Collecting webencodings
Downloading webencodings-0.5.1-py2.py3-none-any.whl (11 kB)
Collecting wcwidth
Downloading wcwidth-0.1.9-py2.py3-none-any.whl (19 kB)
Collecting attrs>=17.4.0
Downloading attrs-19.3.0-py2.py3-none-any.whl (39 kB)
Requirement already satisfied: importlib-metadata; python_version < "3.8" in /usr/local/lib/python3.6/dist-packages (from jsonschema!=2.5.0,>=2.4->nbformat->notebook->jupyter) (1.6.0)
Collecting pyrsistent>=0.14.0
Downloading pyrsistent-0.16.0.tar.gz (108 kB)
|████████████████████████████████| 108 kB 202 kB/s 
Collecting parso>=0.7.0
Downloading parso-0.7.0-py2.py3-none-any.whl (100 kB)
|████████████████████████████████| 100 kB 243 kB/s 
Collecting pyparsing>=2.0.2
Downloading pyparsing-2.4.7-py2.py3-none-any.whl (67 kB)
|████████████████████████████████| 67 kB 75 kB/s 
Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.6/dist-packages (from importlib-metadata; python_version < "3.8"->jsonschema!=2.5.0,>=2.4->nbformat->notebook->jupyter) (3.1.0)
Building wheels for collected packages: prometheus-client, tornado, pandocfilters, backcall, pyrsistent
Building wheel for prometheus-client ( ... done
Created wheel for prometheus-client: filename=prometheus_client-0.7.1-py3-none-any.whl size=41402 sha256=1877caa0c6edd08a07b1fa309bfbdda584bd76e844bdd201b86be6d7d22cafbe
Stored in directory: /tmp/pip-ephem-wheel-cache-8bi_3gi1/wheels/1d/4a/79/a3ad3f74b3495b4555359375ca33ad7b64e77f8b7a53c8894f
Building wheel for tornado ( ... done
Created wheel for tornado: filename=tornado-6.0.4-cp36-cp36m-linux_x86_64.whl size=427632 sha256=d6aafe6d2604804cf85b680683a70cef28b97f1eb209117421a48c1aa9ab7c68
Stored in directory: /tmp/pip-ephem-wheel-cache-8bi_3gi1/wheels/37/a7/db/2d592e44029ef817f3ef63ea991db34191cebaef087a96f505
Building wheel for pandocfilters ( ... done
Created wheel for pandocfilters: filename=pandocfilters-1.4.2-py3-none-any.whl size=7855 sha256=422d885d227893b61571ea6ff8f118801dc5949559cdb74af149b10804d8ebbc
Stored in directory: /tmp/pip-ephem-wheel-cache-8bi_3gi1/wheels/46/c4/40/718c6fd14c2129ccaee10e0cf03ef6c4d01d98cad5dbbfda38
Building wheel for backcall ( ... done
Created wheel for backcall: filename=backcall-0.1.0-py3-none-any.whl size=10412 sha256=dc8f81fbfca6f8b8b1321046de42f718a1f7b1cc1ce997bbc18228a2c9d3c0ff
Stored in directory: /tmp/pip-ephem-wheel-cache-8bi_3gi1/wheels/b4/cb/f1/d142b3bb45d488612cf3943d8a1db090eb95e6687045ba61d1
Building wheel for pyrsistent ( ... done
Created wheel for pyrsistent: filename=pyrsistent-0.16.0-cp36-cp36m-linux_x86_64.whl size=97738 sha256=f6ffcf09823e6aadbd67a5b06ba106699614a0b3add6f7a0ba92a1e6fa2ea49f
Stored in directory: /tmp/pip-ephem-wheel-cache-8bi_3gi1/wheels/d1/8a/1c/32ab9017418a2c64e4fbaf503c08648bed2f8eb311b869a464
Successfully built prometheus-client tornado pandocfilters backcall pyrsistent
Installing collected packages: ptyprocess, tornado, terminado, ipython-genutils, decorator, traitlets, jupyter-core, pyzmq, jupyter-client, Send2Trash, pyparsing, packaging, webencodings, bleach, pygments, mistune, jinja2, pandocfilters, attrs, pyrsistent, jsonschema, nbformat, testpath, defusedxml, entrypoints, nbconvert, wcwidth, prompt-toolkit, pickleshare, parso, jedi, backcall, ipython, ipykernel, prometheus-client, notebook, widgetsnbextension, ipywidgets, qtpy, qtconsole, jupyter-console, jupyter
Successfully installed Send2Trash-1.5.0 attrs-19.3.0 backcall-0.1.0 bleach-3.1.5 decorator-4.4.2 defusedxml-0.6.0 entrypoints-0.3 ipykernel-5.2.1 ipython-7.13.0 ipython-genutils-0.2.0 ipywidgets-7.5.1 jedi-0.17.0 jinja2-2.11.2 jsonschema-3.2.0 jupyter-1.0.0 jupyter-client-6.1.3 jupyter-console-6.1.0 jupyter-core-4.6.3 mistune-0.8.4 nbconvert-5.6.1 nbformat-5.0.6 notebook-6.0.3 packaging-20.3 pandocfilters-1.4.2 parso-0.7.0 pickleshare-0.7.5 prometheus-client-0.7.1 prompt-toolkit-3.0.5 ptyprocess-0.6.0 pygments-2.6.1 pyparsing-2.4.7 pyrsistent-0.16.0 pyzmq-19.0.0 qtconsole-4.7.3 qtpy-1.9.0 terminado-0.8.3 testpath-0.4.4 tornado-6.0.4 traitlets-4.3.3 wcwidth-0.1.9 webencodings-0.5.1 widgetsnbextension-3.5.1


Yeah, this is pretty long list of packages required for jupyter. !

Once installation is completed, you can start jupyter using following command

$ jupyter notebook --allow-root
[I 20:44:06.979 NotebookApp] The port 8888 is already in use, trying another port.
[I 20:44:06.982 NotebookApp] Serving notebooks from local directory: /home/username/code/quant
[I 20:44:06.982 NotebookApp] The Jupyter Notebook is running at:
[I 20:44:06.982 NotebookApp] http://localhost:8889/?token=94cc0863965bf1d2751ad8a7a4b26d08f1b9f0be4f380c9a
[I 20:44:06.982 NotebookApp] or
[I 20:44:06.982 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 20:44:06.987 NotebookApp]

To access the notebook, open this file in a browser:
Or copy and paste one of these URLs:
[W 20:44:09.233 NotebookApp] 404 GET /api/kernels/7f717081-a79b-4170-b5be-c7e548ea28c7/channels?session_id=a53b179c3d2c4deda89418767c9bb6b9 ( Kernel does not exist: 7f717081-a79b-4170-b5be-c7e548ea28c7
[W 20:44:09.249 NotebookApp] 404 GET /api/kernels/7f717081-a79b-4170-b5be-c7e548ea28c7/channels?session_id=a53b179c3d2c4deda89418767c9bb6b9 ( 19.55ms referer=None

and then you can access your jupyter notebooks at http://localhost:8889
Here is how it looks

Hope this helps.

Using Slugify with Django blog to create slug or url

In this article we will have a look at how to use Django utility to create slug field automatically and most importantly, you can create slugs in languages other than English too.

For creating blog application, please refer to post how to create Blog app using Django.

Once you create blog application, you admin screen will look something like below.

Here if you see carefully, slug is user input field, now we want to make it auto created field by making some changes into

from django.db import models
from django.contrib.auth.models import User
from django.utils.text import slugify                                # add this

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True,editable=False)  # Note the changes here, editable is false.
    author_local = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts',default="admin")
    updated_on = models.DateTimeField(auto_now= True)
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)
    post_type = models.CharField(max_length=15,choices=POST_CHOICES,default=None,blank=True)
    category = models.CharField(max_length=50,default=None,blank=True)
    featured_image = models.ImageField(upload_to='img', blank=True, null=True)

    class Meta:
        ordering = ['-created_on']

    def save(self, *args, **kwargs):                                  # add this
        self.slug = slugify(self.title, allow_unicode=True)           # add this
        super().save(*args, **kwargs)                                 # add this

    def __str__(self):
        return self.title

Since you are making changes in, you need to run following commands


$python3.6 makemigrations yourappname
$python3.6 migrate


Now access admin again, it will look like below and once you save the post, slug is automatically created.

Since we are using Unicode, it works for Devanagari script (Marathi and Hindi), I did not test for other languages but it would work for other languages too.


You might be wondering why content text field has options like WordPress editor in my screenshot. Please refer to post How to add Summernote WYSIWYG Editor in Django.

How to add Summernote WYSIWYG Editor in Django

After I created a blog application, biggest hurdle from using it is its admin editor. Anyone who has every used wordpress or any otehr blogging platform will not be OK to use simple text editor. I was searching for options to make the text field something like wordpress. I came across two options tinymce editor and Summernote.

I looked at install steps of tinymce and it looked complicated, I did not try and see if this works. When I looked at Summernote, it look simple and straghtforward and I decided to give it a try. Its very simple and it works perfectly fine.

Here are the steps for installtion

Step#1 Install Summernote package.

Install it just like any other python package. If you are using virtualenv, please make sure you install it in virtualenv

$pip install django-summernote
python -m pip install Pillow

Step#2 Changes in

Add this to main file

urlpatterns = [
    path('summernote/', include('django_summernote.urls')),
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  #add this for media

Step#3 Changes in

Add django_summernote in installed apps in file.

    'blog.apps.BlogConfig', # add this statement
    'ifsccode.apps.IfsccodeConfig', # add this statement
    # 'django.contrib.sites',
    'django_summernote',          # This is added


Also add media folder settings at the end of

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'


Step#4 Changes in

Changes in

from django.contrib import admin
from django_summernote.admin import SummernoteModelAdmin

from .models import Post, Category, Comment, Tag


class PostAdmin(SummernoteModelAdmin):    #added this
    summernote_fields = ('content',)      #added this, PostAdmin)

Please note that in above table, I have content field under Post

Step#5 Changes in Templates

Finally and most importantly, when you are displaying the field, mark it as safe.

<div id="postdetails">{{post.content|safe}}</div>

once this is done

Django admin CSS or static file not working [Solved]

You might have came across a situation where your application works perfectly fine on local machine but when deployed to production, everything works except admin section, technically it functions as expected but it does not have CSS. Why this happens ?

If you want to recreate this problem, just following in from True to False.

DEBUG = False
This happens because you application is not able to load css files for admin  functionality. To address this problem, please follow below mentioned steps.

Step#1 collectstatic

First you need to create a folder called static in your project root directory, then run below command
$python3.6 collectstatic.
This will move admin css files under static folder. You can see new folder created under static folder called admin. This folder will have admin view related css, js , fonts, img.
You might wonder where were these files before ? these were server from site-packages folder of Django. You dont need to dig details here, but if you want you can.

Step#2 Change server config.

When you are running, runserver, you are running development server and it does a lot of things for you, including serving of static files but in production, Django expects that the static files will be served by your serer.

This is not difficult at all, just have below changes done to your nginx server config.

server {

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/domainname.sock;

    location /static {                        # add this
       alias /var/www/domainname/static;      # add this
    }                                         # add this


if you are hosting django application using uwsgi and NGINX, this will work for you. I am not sure about gunicorn server. You can check post deploying django with uwsgi and nginx for deployment of your application to server.

First make sure you application is working on production server and then work on to make admin successfully.  Deploying Django to server has its own challenges, don’t make it more complicated by adding this change too. Attack problems one at a time.

Please let me know if you faced any issue while getting this working.

Create html or xml sitempa for Django app

If you are creating any content based website, it is utmost important to have a sitemap.   At first it looks like sitemap creation is complex using Django but if you understand the process its fairly simple. You can follow below steps to create simple sitemap.xml

Step#1 Config changes.

Add 'django.contrib.sitemaps', in INSTALLED_APPS section of
Also ensure following settings for TEMPLATES

        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            BASE_DIR + '/templates/', # add this line
        'APP_DIRS': True,

Step#2 Create

Now cd to subapp directory and create file as below

from django.contrib.sitemaps import Sitemap
from .models import Post
class PostSitemap(Sitemap):    
    changefreq = "monthly"
    priority = 0.9
    def items(self):
        return Post.objects.all()
    def lastmod(self, obj):
        return obj.created_on

changefreq can be hourly, monthly, never etc.

Most important point to be noted here. Whichever data model you are using, make sure it has function get_absolute_url()  defined.
for example

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True)
    author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)
    category = models.ForeignKey(Category, on_delete = models.CASCADE,verbose_name="Category",default=None,blank=True)
    updated_on = models.DateTimeField(auto_now= True)
    tags = models.ManyToManyField(Tag, related_name='rel_posts',default=None,blank=True)
    featured_image = models.ImageField(upload_to='img', blank=True, null=True)

    class Meta:
        ordering = ['-created_on']

    def get_absolute_url(self): #this is added for sitemap
        return '/'+self.slug
    def __str__(self):
        return self.title

Now make changes into blog/

from django.urls import path
from . import views
from django.contrib.sitemaps.views import sitemap
from .sitemaps import PostSitemap

sitemaps = {
    'posts': PostSitemap

app_name = 'blog'
urlpatterns = [
    path('', views.index, name='index'),  
    path('sitemap.xml', sitemap, {'sitemaps' : sitemaps } , name='sitemap'),  

Now if you try to access sitemap.xml, you can see it

This XML file does not appear to have any style information associated with it. The document tree is shown below.

Please notethat this siitemap is accessible from subapp. Either you need to make this subapp accessible on main url or this sitempa will be available at url something like below

Please let me know if this works for you or if you faced any issue while making this work.

Deploy Django Application using NGINX, uWSGI

After developing couple of django application and testing them using inbuild development server (runserver), I was ready to deploy my Django application to VPS but littile did I know, deployment of django application is a big task itself.

I first started using official tutorial from Digital Ocean How To Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 16.04 but it turned out to be two complex. I spent almost a day but I ended up nowhere. I was searching for otherway of deployment thats when I came across uWSGI. You can find official documentation here. Setting up Django using uWSGI was not cakewalk either but I found it easy as compared to Gunicorn. In this effort, i spent almost two days (not whole days, may be  hours in total) but finally I got it working. I am documenting step by step actions for you to help.

Step#1 Prepare environment

$sudo apt-get update
$sudo apt-get upgrade
$sudo python3.6 -m pip install virtualenv

Now let us create a django application on server. If you have already developed your application, you can deploy it to server using git as explained here or copy code using FileZilla or some other ways. For simplicity, I am creating an application.

$django-admin startproject yourapp
$cd yourapp
$python3.6 startapp blog
$virtualenv venvft
created virtual environment in 453ms
creator CPython3Posix(dest=/var/www/yourapp/venvft, clear=False, global=False)
seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, via=copy, app_data_dir=/home/user/.local/share/virtualenv/seed-app-data/v1.0.1)
activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator

$source venvft/bin/activate
$pip install django 
$pip install psycopg2

Please note the packages are installed inside virtual environment using pip install but outside it using command $sudo python3.6 -m pip install psycopg2. This command will not work inside virtual environment. Please don’t ask me why, I only know how. You can deactivate virtual environment at this stage.

Step#2 Django Application set up.

You already know what you need to do to set up django application. Changes to etc. For more details, you can refer to this post Building blog application using django.

Once basic setup is done, you need to run following commands

$ python3.6 makemigrations blog
$ python3.6 migrate

Before we test the application, please update ALLOWED_HOSTS in Here ‘NNN.NN.NN.NNN’ stands for your server ip

ALLOWED_HOSTS = ['NNN.NN.NN.NNN','','','localhost','','']

Once done, let us test our application using our old development server. This is to ensure, our application is working fine. If you face any issue at this stage, it has nothing to do with server setup, tourbleshoot any Django related issue here. Only if you can run your application on development server, proceed to next step

python3.6 manage.oy runserver

You can open new command prompt and test this using following


Step#3 Run using uWSGI server

Now lets run it using uwsgi using following command

sudo uwsgi --http --home /var/www/yourapp/venvft --chdir /var/www/yourapp/yourapp --wsgi-file /var/www/yourapp/yourapp/

Toubleshooting. There is possibility that you might get below error

ModuleNotFoundError: No module named 'yourapp'
unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 28959, cores: 

In this case, you need to make few changes to yourapp/yourapp/ file

import os
import sys #added this

from django.core.wsgi import get_wsgi_application

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #added this
sys.path.append(BASE_DIR) #added this

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yourapp.settings')

application = get_wsgi_application()

I have added comments about which line needs to be added. Now test again and it should work file.

Step# 4 uWSGI setup

Create a yourapp.ini file @ location /home/username/uwsgi/sites as below

home = /var/www/yourapp/venvft
chdir = /var/www/yourapp/yourapp
wsgi-file = /var/www/yourapp/yourapp/

#http =

socket = /run/uwsgi/yourapp.sock
vacuum = true
chown-socket = username:www-data
chmod-socket = 666

Please change yourapp and username in this file as pr your names

Now cd /etc/systemd/system/ and sudo nano uwsgi.service

#Description=uWSGI Emperor service
Description=uWSGI Emperor

ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown username:www-data /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /home/username/uwsgi/sites


Here also. change the username to match yours.

After this is done cd /var/www/ and change ownership of project folder

sudo chown www-data:www-data -R yourapp

Step#5 NGINX setup

This is simplest of all. Simply use following code.

server {

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/yourapp.sock;

Now run following commands

sudo service nginx stop
sudo service uwsgi stop
sudo service nginx start
sudo service uwsgi start

Restart can also work but I prefer to stop and start.

Now before you check your application on your browser cd /run/uwsgi
and check if this folder has any files

If there is no error you will see filename yourapp.sock. Now you are all set to access your application using its domain name.

Following links were very helpful for me. If you need any clarification or facing error, you can let me know or check below links