My HP

19th April, 2020 | Tutorials |

How to start a Django application from scratch on HostPresto!

Looking for Django hosting? Check out our optimised packages.

Get Django Hosting

In this tutorial we will create a brand new Django application on HostPresto!

Let’s start by setting up our environment:


Getting Started with Django on HostPresto

Django is a non-profit, open source web framework based on the Python programming language maintained by Django Software Foundation, you can read more about the framework here: https://www.djangoproject.com . All of HostPresto Web hosting packages support Python and Django, this tutorial will help you setup and install Django on one of our Django Web Hosting packages.

Setting up a Python application:

For the purpose of this tutorial we're using our demo cPanel account which has the website address apps.hostpresto.com, you would substitute this and any example folder/project names with your own. First thing you will need to do is login your cPanel, a helpful guide on this can be found in our how to login to cPanel help article.  In cPanel you will then need to go to the SOFTWARE section and select Setup Python App. Then click on CREATE APPLICATION.

HostPresto! Uses software from Passenger (https://www.phusionpassenger.com/) to set up Python applications, including Django. Select the latest Python version in the first field. It is 3.7.3 at the time of writing but you should always go for the latest version unless you specifically require an older one.

In Application root type in the name of your application directory, this must be different to the public folder for the django website. For example lets say we want to install Django at the website address https://apps.hostpresto.com then the public folder would be located in public_html. For the application folder it makes sense not to have it in public_html but on the same level and simply called "myapp" so go ahead and enter "myapp" in the "application root" box. This will automatically create the "myapp" folder for you.

Select ‘apps.hostpresto.com’ as the Application URL in the next line.

Leave Application startup file and Application Entry point empty – the system will create this file by its own rules and let it do it.

The last thing – it's sensible to set up a log file (Passenger log file) – enter /home/hpapps/myapp.log in the Passenger Log File box,  then click on CREATE.


Point your browser to your application website address/URL, for this this example it would be https://apps.hostpresto.com, you should see something like this:

This means we have successfully created a virtual environment for our Python application.


Installing Python packages:

Yes, we can do it directly from the web interface (by going to the ‘requirements.txt’ file - if you have this file in root subdirectory, In the ‘Configuration files’ section, click ADD, then click ‘Run Pip install'), but we won’t do it this way. Let’s do it the traditional way, via running shell commands. We will need to use shell commands anyway, so let’s go to the command line straight away.

We need to make a ssh connection to our server. If you are on Windows, I recommend to use a program called PuTTY. Use your cPanel username and password (not client area password!) and change port 22 to 88 for the ssh connection.

Once logged in, activate your project virtual environment and cd into the project directory. How do you do this? Actually cPanel contains a useful hint: at the top of the page the command is displayed for you:

Enter to the virtual environment. To enter to virtual environment, run the command: source /home/hpapps/virtualenv/myapp/3.7/bin/activate && cd /home/hpapps/myapp

Just click on the command shown on your cPanel and it will be copied to your clipboard. Paste the command to PuTTY terminal window and run it – now you are in your project directory and the virtual environment has been activated. First of all, let’s upgrade pip – run the following command:

pip install --upgrade pip

Next, we will install Django:

pip install django

Django allows you to use various database types such as PostgreSQL and SQLite which are fully supported by HostPresto but for this tutorial we're going to use good old MySQL.

pip install mysqlclient

I highly recommend to install WhiteNoise for managing static files, this will make life much easier:

pip install whitenoise

Install django-environ which we will use to manage application specific variables such as your MySQL database password. Said variables will be stored in a .env file which is a preferred method to use over the environment variables facility within the cPanel:

pip install django-environ

To finalise set up, let's create the requirements.txt file:

pip freeze > requirements.txt

This command will create the requirements.txt file, which can be used to re-create the environment if needed. We don't need this file right now right here, but it's a good practice to have it at hand just in case.


Creating a project:

Run the following command:

django-admin startproject myapp_project .

(Please notice the dot at the end of command. This dot tells django-admin to create a project in the current directory. Otherwise, it will create a subdirectory 'myapp_project' in the current directory - this is not what we want.)


Creating MySQL database for the project:

This is easy. In cPanel, go to DATABASES – MySQL Database Wizard.

Type in a name for a database. Let’s call it 'myapp' so we can easily identify the django database later if we need to.

cPanel automatically prefixes the database name with your cpanel username, e.g. hpapps_, so the full name will be 'hpapps_myapp'.

Click on Next Step, provide a name and a password for the new database user (let’s give the user the same name: 'hpapps_myapp'). Don’t forget to make a note of the newly created password – we’ll need it in a minute.

Click Next.

On Step 3 check the ALL PRIVILEGES tick box.

Click Next.


Configuring Django to use MySQL:

In the cPanel file manager, navigate to /home/hpapps/myapp/myapp_project. This subdirectory should contain the settings.py file. Open this file in the file editor. First thing we need to do is import the environ module this is so the settings can access environment variables, which will be used for accessing the MySQL password. Right at the top of the file you should see the following line:

from pathlib import Path

Add the code to import the environ module and initialise it, your settings file should now look like this at the top.

from pathlib import Path
import environ
# Initialise environment variables
env = environ.Env()
environ.Env.read_env()

Next find the DATABASES section. Replace the whole section with the following lines:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': env('DATABASE_NAME'),
'USER': env('DATABASE_USER'),
'PASSWORD': env('DATABASE_PASS'),
'HOST': 'localhost',
}
}

It’s not a good idea to hard code the database connection details in the file, so we will read it from an .env file instead. In the same directory as settings.py, create a file called ‘.env’ and add your database connection details (Replace hpapps_myapp with your own name you have created in the previous step). Make sure you don’t use quotations around strings.

DATABASE_NAME=hpapps_myapp
DATABASE_USER=hpapps_myapp
DATABASE_PASS=supersecretpassword

Configure allowed hosts

We need to add our domain name to the settings.py ALLOWED_HOSTS settings variable, reopen myapp_project/settings.py and replace the following:

ALLOWED_HOSTS = []

With

ALLOWED_HOSTS = ['apps.hostpresto.com']

Be sure to replace apps.hostpresto.com with your own domain name.


Configuring passenger_wsgi.py:

Return to your cPanel – Setup Python App page.

You will see the Application startup file and Application Entry point fields are populated now.

The Application startup file is called passenger_wsgi.py. Find this file in the root folder of our project. Open it in File Manager. It should look like this:

import os
import sys

sys.path.insert(0, os.path.dirname(__file__))

def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) message = 'It works!\n' version = 'Python %s\n' % sys.version.split()[0] response = '\n'.join([message, version]) return [response.encode()]

We don’t need all of this, so delete the content and replace it with the following:


import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp_project.settings')
application = get_wsgi_application()

Then RESTART the application again and create the app:

python manage.py startapp myapp

Refresh the https://apps.hostpresto.com page in your web browser, and you should then see:

Congratulations! Our first Django application is up and running!


Further steps:

OK, Let's continue forward. Let's try the admin page: https://apps.hostpresto.com

It looks like our web application isn't currently seeing the .css files, causing the formatting to look broken.

Luckily, we already installed the WhiteNoise package, which will help us with just one line in settings.py. Open your settings.py file again in the cPanel file editor and add the below to the MIDDLEWARE section:

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', #new
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

RESTART the app once more and then refresh the page in your web browser:

Much better!

This is what WhiteNoise does for us - no need to run the collectstatic command. All static files are now being served directly from the Python server.

The next thing we need to migrate is the database. We didn't write a single line of code yet, but Django did a lot for us. So let's migrate by running the below command in our SSH terminal:

python manage.py migrate

Next, let's create a superuser:

python manage.py createsuperuser

Now you can log in to admin page via your web browser.


Creating a meaningful app:

OK, let's create something meaningful. In this example lets create a simple Contact list.

First of all, we need to create a model. Let's open a nearly empty file in the cPanel file manager: myapp_project/models.py and add some content to it. A very simple Contact model:

# Create your models here.
class Contact(models.Model):
forename = models.CharField(max_length=100)
surname = models.CharField(max_length=100)
email = models.EmailField(max_length=100)

def __str__(self): return f"{self.forename} {self.surname}: {self.email}"

We also need to update our settings.py file one more time. We need to add our app, myapp_project, to the INSTALLED_APP section:

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

'myapp_project', #new ]

Let's add our new model to the admin area. Add these lines to the myapp_project/admin.py file:

from django.contrib import admin

# Register your models here. from .models import Contact admin.site.register(Contact)

In the SSH console, run following command:

python manage.py makemigrations

Then:

python manage.py migrate

Next, RESTART the app and then login to the admin interface in your web browser, using credentials you supplied to the createsuperuser command

In this tutorial, I won't go further into creating views, forms and other common stuff. All this is common to any hosting provider, so you will find tons of useful tutorials on the Internet.

Instead, I'd like to pay some attention to details, specific for HostPresto. Namely, testing.


Testing our app:

Let's create a very simple test in our myapp/tests.py file:

from django.test import TestCase

# Create your tests here. from .models import Contact

class ContactModelTests(TestCase): def test_contact_save(self): contact = Contact() contact.save()

self.assertNotEqual(contact.id, None,'id is autocreated') self.assertEqual(len(Contact.objects.all()),1,'Exactly 1 record in db after save')

If we try to run test the usual way:

python manage.py test

Most likely, we will get an error, something like this:

Got an error creating the test database: (1044, "Access denied for user 'hpapps_myapp'@'localhost' to database 'test_hpapps_myapp'")

This is because Django tries to create a new database for testing, and our database user does not have enough rights to create another database on the MySQL server.

OK, we can create an empty database via cPanel - MySQL Databases, and then use the parameter --keepdb, but there is another problem: cPanel requires that the database name starts with 'hpapps_'. We cannot prepend 'test_' to the name.

OK, there are still possibilities. Let's create a database with the name 'hpapps_myapp_test'. This is allowed. How should we tell Django to use this name? We need to edit the myapp_project/settings.py file one more time and add an option to the DATABASES section:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': env('DATABASE_NAME'),
'USER': env('DATABASE_USER'),
'PASSWORD': env('DATABASE_PASS'),
'HOST': 'localhost',

'TEST': { 'NAME': 'hpapps_myapp_test', } } }

Now we can run tests with the following command:

python manage.py test --keepdbNote: Don't even think of using the live db for testing - running tests on live will empty all data!

Logging:

Setting up logging in Django is really complicated. I won't go in to detail here, but what can we do with the default configuration?

Actually, it just works, although to use it is not very convenient.

To demonstrate logging, let's add some logging to our model via the myapp/models.py file:

from django.db import models
import logging
logger = logging.getLogger(__name__)

# Create your models here. class Contact(models.Model): forename = models.CharField(max_length=100) surname = models.CharField(max_length=100) email = models.EmailField(max_length=100)

def __str__(self): return f"{self.forename} {self.surname}: {self.email}"

def save(self, *args, **kwargs): super().save(*args, **kwargs) # Call the "real" save() method. logger.error( f"Contact saved with id={self.id}.")

The default logging level is set to ERROR (despite whatever is written in Django documentation - probably Passenger or cPanel somehow interferes with it), so don't bother using logger.debug of logger.info.

Now go to your apps admin interface and create a few Contacts to see how it works.

Where can we see the logs?

Remember, there was a Passenger log file, of which the name we set up in the SOFTWARE - Setup Python App panel? (in this example we called it /home/hpapps/myapp.log).

All server logs from our Python application go into this file, and logs generated by calling logger.error or logger.critical will also go into this file. Not very convenient, but at least we can use the default Python logging mechanism.

Another useful option would be to install Django Debug Toolbar, although it still requires some configuration for optimal use.


Conclusion:

In this tutorial, we have created a very basic Django application. This application does very little, and does not even have a proper front end - all it has is an admin area.

But we covered very important details, related to the specifics of How to set up a Python environment within cPanel on HostPresto!, how to switch to MySQL database usage, how to set up a passenger_wsgi.py file, how to use logging with minimum configuration effort and even how to test our application.

In most cases, using a remote server as a development server is not a very good idea. It would be better to install Python and all development tools locally and only use the remote server as a test or production environment.

Looking for Django hosting? Check out our optimised packages.

Get Django Hosting

Comments