Difference between revisions of "Django"

From DUNE
Jump to navigation Jump to search
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
=Installation=
 
=Installation=
There are a few ways to install Django, perhaps the cleanest and easiest is by using ''pip''. With Python 3+
+
==pip==
you will need to install pip3 first, like
+
There are a few ways to install Django, perhaps the cleanest and easiest is by using ''pip''.
 +
With Python 3+ you will need to install pip3 first, like
 
<pre>
 
<pre>
 +
# Ubuntu
 
apt-get install python3-pip
 
apt-get install python3-pip
 +
#
 +
pip3 install django==1.10 # or any other version required
 
</pre>
 
</pre>
  
After that, Django is obtained by
+
 
 +
To check which version of Django you are using at the moment, start interactive Python and use this:
 
<pre>
 
<pre>
pip3 install django==1.10
+
import django
 +
django.VERSION
 
</pre>
 
</pre>
...and other versions available instead of 1.10 can be specified if needed. An important and popular Django add-on package "tables2" can be added likewise:
+
 
 +
Or,
 +
<pre>
 +
python3 -m django --version
 +
</pre>
 +
 
 +
==Tables2==
 +
 
 +
The popular Django add-on package "tables2" can be added likewise:
 
<pre>
 
<pre>
 
pip3 install django-tables2
 
pip3 install django-tables2
 
</pre>
 
</pre>
  
To check which version of Django you are using at the moment, start interactive Python and use this:
+
If one needs to verify the successful installation of this package, the following needs to be done
 +
in an interactive Python session before "import" is attempted:
 
<pre>
 
<pre>
import django
+
>>> from django.conf import settings
django.VERSION
+
>>> settings.configure()
 
</pre>
 
</pre>
  
=DB=
+
=Databases=
 +
==sqlite==
 
Django comes packaged with a sqlite database. It will work fine for initial development and testing,
 
Django comes packaged with a sqlite database. It will work fine for initial development and testing,
 
but it won't handle concurrency in most cases (e.g. multiple clients of same type updating same
 
but it won't handle concurrency in most cases (e.g. multiple clients of same type updating same
Line 31: Line 47:
 
PostgreSQL, MySQL, Oracle etc.
 
PostgreSQL, MySQL, Oracle etc.
  
=Deploying DB for Django=
+
==Deploying DB for Django==
==sqlite permissions==
+
===sqlite permissions===
 
Assuming you are using sqlite, the file permissions on the DB file do matter if when you deploy under Apache.
 
Assuming you are using sqlite, the file permissions on the DB file do matter if when you deploy under Apache.
 
So you either need to set wide permissions (may not be a good idea depending on the security situation) or
 
So you either need to set wide permissions (may not be a good idea depending on the security situation) or
 
change the owner to "www-data" (on Ubuntu) or "apache" (on CentOS). Other OS may require similar tweaks.
 
change the owner to "www-data" (on Ubuntu) or "apache" (on CentOS). Other OS may require similar tweaks.
  
==PostgreSQL==
+
===PostgreSQL===
 
An example of the "settings.py" clause:
 
An example of the "settings.py" clause:
 
<pre>
 
<pre>
Line 51: Line 67:
 
}
 
}
 
</pre>
 
</pre>
 +
==Transactions==
 +
Utilizing transactions may become necessary in scenarios when concurrency needs to be handled.
 +
In addition, locking specific rows for update can be achieved transparently (if the DB backend
 +
supports it) in the following manner:
 +
<pre>
 +
entries = Entry.objects.select_for_update().filter(author=request.user)
 +
</pre>
 +
 +
This should be done within a transaction block which perhaps throws an exception if the row is locked.
 +
 +
==Database Routers and Migration to a New Database==
  
 +
In case multiple databases are required in the app, one needs to implement database routers.
 +
This is not difficult since numerous examples can be easily found. However, there are recipes
 +
that must be followed to make migrations work correctly. In the following example, we want to
 +
use a newly created database "users" to keep auth/admin info separate from the main content.
 +
The migrations should refer to that specific database, and not just to the app name as recommended
 +
in a few places:
 +
 +
<pre>
 +
$ ./manage.py migrate --database=users
 +
# and also requires explicit reference to the database when managing users:
 +
$ ./manage.py createsuperuser --database=users
 +
</pre>
 +
 +
In the latter command, if the database is not explicitly mentioned, the superuser will be created
 +
in the previously deployed database, not in the new instance. Even the prior migration won't change
 +
this behavior, so again the exact reference must be there.
  
 
=The Development Server=
 
=The Development Server=
Line 63: Line 106:
  
 
If 0.0.0.0 is skipped, the server will work but won't be accessible from a different machine.
 
If 0.0.0.0 is skipped, the server will work but won't be accessible from a different machine.
 +
 +
=Admin Pages=
 +
==Serving Styles for Amdin pages on a real Web server==
 +
There is plenty of information on setting up the correct function of the Django Admin pages,
 +
however there is one thorny item which is styling these pages when running on a real Web server
 +
(they will style correctly on the development server but this may break).
 +
 +
The simplest recipe I found so far (and I think I invented this myself) is to just copy
 +
the needed sources from the "admin" folder in your Django package tree, into the "static"
 +
directory, assuming you have configured the latter correctly for your Web server. For example,
 +
<pre>
 +
sudo cp -r /usr/local/lib/python3.5/site-packages/django/contrib/admin/static/admin /var/www/static
 +
</pre>
 +
fixes the problem.
 +
 +
==Admin password reset==
 +
Start Django shell:
 +
<pre>
 +
python manage.py shell
 +
</pre>
 +
 +
...and check superusers:
 +
<pre>
 +
from django.contrib.auth.models import User
 +
User.objects.filter(is_superuser=True)
 +
</pre>
 +
 +
For a given user, the password can be set as follows:
 +
<pre>
 +
usr = User.objects.get(username='your username')
 +
usr.set_password('raw password')
 +
usr.save()
 +
</pre>

Latest revision as of 16:05, 2 June 2019

Installation

pip

There are a few ways to install Django, perhaps the cleanest and easiest is by using pip. With Python 3+ you will need to install pip3 first, like

# Ubuntu
apt-get install python3-pip
#
pip3 install django==1.10 # or any other version required


To check which version of Django you are using at the moment, start interactive Python and use this:

import django
django.VERSION

Or,

python3 -m django --version

Tables2

The popular Django add-on package "tables2" can be added likewise:

pip3 install django-tables2

If one needs to verify the successful installation of this package, the following needs to be done in an interactive Python session before "import" is attempted:

>>> from django.conf import settings
>>> settings.configure() 

Databases

sqlite

Django comes packaged with a sqlite database. It will work fine for initial development and testing, but it won't handle concurrency in most cases (e.g. multiple clients of same type updating same DB tables). There are a few reasons for that, such as:

  • lack of table/row lock capability
  • presence of the file lock on the whole DB file

If the application requires any level of concurrency a different DB engine will be needed such as PostgreSQL, MySQL, Oracle etc.

Deploying DB for Django

sqlite permissions

Assuming you are using sqlite, the file permissions on the DB file do matter if when you deploy under Apache. So you either need to set wide permissions (may not be a good idea depending on the security situation) or change the owner to "www-data" (on Ubuntu) or "apache" (on CentOS). Other OS may require similar tweaks.

PostgreSQL

An example of the "settings.py" clause:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'foo',
        'USER': 'bar',
        'PASSWORD': '***',
        'HOST': '',
        'PORT': '',
    }
}

Transactions

Utilizing transactions may become necessary in scenarios when concurrency needs to be handled. In addition, locking specific rows for update can be achieved transparently (if the DB backend supports it) in the following manner:

entries = Entry.objects.select_for_update().filter(author=request.user)

This should be done within a transaction block which perhaps throws an exception if the row is locked.

Database Routers and Migration to a New Database

In case multiple databases are required in the app, one needs to implement database routers. This is not difficult since numerous examples can be easily found. However, there are recipes that must be followed to make migrations work correctly. In the following example, we want to use a newly created database "users" to keep auth/admin info separate from the main content. The migrations should refer to that specific database, and not just to the app name as recommended in a few places:

$ ./manage.py migrate --database=users
# and also requires explicit reference to the database when managing users:
$ ./manage.py createsuperuser --database=users

In the latter command, if the database is not explicitly mentioned, the superuser will be created in the previously deployed database, not in the new instance. Even the prior migration won't change this behavior, so again the exact reference must be there.

The Development Server

Not suitable for real life deployment, as the name suggests it's for development only. In addition to potential security issues, it may be challenging for thread safety unless one disables multithreading. If you want to access the development server on a local network, from a different computer, the command line below can serve as an example of how to start it:

./manage.py runserver 0.0.0.0:8000

If 0.0.0.0 is skipped, the server will work but won't be accessible from a different machine.

Admin Pages

Serving Styles for Amdin pages on a real Web server

There is plenty of information on setting up the correct function of the Django Admin pages, however there is one thorny item which is styling these pages when running on a real Web server (they will style correctly on the development server but this may break).

The simplest recipe I found so far (and I think I invented this myself) is to just copy the needed sources from the "admin" folder in your Django package tree, into the "static" directory, assuming you have configured the latter correctly for your Web server. For example,

sudo cp -r /usr/local/lib/python3.5/site-packages/django/contrib/admin/static/admin /var/www/static

fixes the problem.

Admin password reset

Start Django shell:

python manage.py shell

...and check superusers:

from django.contrib.auth.models import User
User.objects.filter(is_superuser=True)

For a given user, the password can be set as follows:

usr = User.objects.get(username='your username')
usr.set_password('raw password')
usr.save()