How to start a Django application from scratch on HostPresto!

Valentine Kulikov
12 min readFeb 15, 2021

--

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

Let’s start by setting up our environment:

Creating a subdomain:

Suppose you have a domain registered with HostPresto! — yourname.xyz. For this tutorial, we will create a subdomain: start.youname.xyz, as you may already have an existing website sitting on the main domain. Adding a subdirectory like youname.xyz/start is less convenient, in our opinion.

Log in into your cPanel and click on Subdomains in the DOMAINS section. Enter ‘start’ into Subdomain field. Select your main domain (youname.xyz) from Domain dropdown. The Document Root field will be auto-populated with ‘start.yourname.xyz’. Let’s accept the default value. Click on Create.

The Subdomain has now been created. If you point your browser to http://start.yourname.xyz, you should normally see an empty directory listing — something like this:

Setting up a Python application:

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. The setup page isn’t very intuitive, in my opinion. But let’s use it anyway.

Select the latest Python version in the first field. It is 3.7.3 at the time of writing.

In Application root type in the directory name we have created in the previous step, relating to your home directory — that is, just ‘start.yourname.xyz’.

Select ‘start.yourname.xyz’ 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/yournamexy/start.log in the Passenger Log File box, replacing “yournamexy” with your cPanel username.

Click on CREATE

Click on START APP

Again, point your browser to http://start.yourname.xyz (or refresh the page if you still have it in one of the tabs). Now it should show 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/yournamexy/virtualenv/start.yourname.xyz/3.7/bin/activate && cd /home/yournamexy/start.yourname.xyz

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

We might need mysqlclient, so let’s install it:

pip install mysqlclient

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

pip install whitenoise

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 start

(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 ‘start’ in the current directory — this is not what we want.)

Now let’s try to create an app:

python manage.py startapp startapp

Most probably, you will get a long list of errors when running the above command. The very last line contains the actual error, something like this:

django.core.exceptions.ImproperlyConfigured: SQLite 3.8.3 or later is required (found 3.7.17).

Actually, it’s good that we’ve run into this error in the very first step. (If not and your command completed successfully you still need to read further!).

As you may remember, for local development you may have used the SQlite server, built-in Python SQL server. This is completely fine for local development, but totally unacceptable for a production server (and we are pretending to create a production server now). So luckily for us, Django doesn’t like the version of the installed SQlite server, so there is no other way than to switch to MySQL. (Traditionally Django uses PostgreSQL but in our case we have MySQL pre-installed on the server, so we will use MySQL)

So let’s return to cPanel and create a MySQL database, using the available cPanel tools.

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 ‘start’ in order to be consistent.

cPanel automatically prefixes the database name with yournamexy_, so the full name will be ‘yournamexy_start’.

Click on Next Step, provide a name and a password for the new database user (let’s give the user the same name: ‘yournamexy_start’). 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/yournamexy/start.yourname.xyz/start. This subdirectory should contain the settings.py file. Open this file in the file editor and find the DATABASES section. Replace the whole section with the following lines:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'yournamexy_start', 'USER': 'yournamexy_start', 'PASSWORD': os.environ['START_DB_PASSWORD'], 'HOST': 'localhost', } }

(Replace yournamexy_start with your own name you have created in the previous step)

It’s not a good idea to hard code the database password, so we will read it from the environment variable instead.

So, return to the SSH console window you have open and set a variable for a password (Replace “your password” in the below command with the password you have chosen when creating a database):

export START_DB_PASSWORD=[your password]

Now you should be able to create an application. Run the following command again:

python manage.py startapp startapp

(Now I realise that I have chosen a bad name for my app — ‘startapp’. startapp is also a command in manage.py, so it is unclear what is what in the above command. It would have been better to name the app, say, ‘first_app’, and the command to create this app would then be: ‘ python manage.py startapp first_app')

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 syssys.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_applicationos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'start.settings') application = get_wsgi_application()

The last thing that we need to do before attempting to run our new Django site, is to set an environment variable for the db password in the Python web application. We did this previously via the SSH command shell, but we now need to do the same for the webserver.

For this, return to the SOFTWARE section in cPanel, go to Setup Python App, click on the Edit (pencil) icon, in line with our newly created application start.yourname.xyz.

In the Environment variables section add a variable named START_DB_PASSWORD with your database password. Click SAVE at the top of the page.

Click RESTART.

Now we are ready to try the application. Point your browser to http://start.yourname.xyz and refresh the page. Most likely you will see a message such as:

DisallowedHost at /Invalid HTTP_HOST header: ‘start.yourname.xyz’. You may need to add ‘start.yourname.xyz’ to ALLOWED_HOSTS. ALLOWED_HOSTS = []

Thankfully, the message is very clear. ALLOWED_HOSTS = [] in settings.py. This default value only allows us to run a web app on the localhost. Now we need to change this. Open your settings.py file and find the line:

ALLOWED_HOSTS = ['polls.yourname.xyz']

Reolace it with the following, Replacing ‘yourname.xyz’ with your actual subdomain:

Then RESTART the application again.

Refresh the http://start.yourname.xyz 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: http://start.yourname.xyz

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.

python manage.py migrate

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 createsuperuser

Next, let’s create a superuser:

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: startapp/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, startapp, 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','startapp', #new ]

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

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

python manage.py makemigrations

In the SSH console, run following command:

python manage.py migrate

Then:

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 startapp/tests.py file:

from django.test import TestCase# Create your tests here. from .models import Contactclass 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')

python manage.py test

If we try to run test the usual way:

Got an error creating the test database: (1044, “Access denied for user ‘yournamexy_start’@’localhost’ to database ‘test_yournamexy_start’”)

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

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 ‘yournamexy_’. We cannot prepend ‘test_’ to the name.

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

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'yournamexy_start', 'USER': 'yournamexy_start', 'PASSWORD': os.environ['START_DB_PASSWORD'], 'HOST': 'localhost','TEST': { 'NAME': 'yournamexy_start_test', } } }

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

Now we can run tests with the following command:

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 startapp/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/yournamexy/start.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.

All files for this tutorial can be found here:

HostPresto! is reasonably priced and reliable hosting. What makes it outstanding — like many hosting providers they give you PHP and MySQL out of the box, but unlike most of other providers, they give you a very simple solution to host almost any kind of application, Node.js, Django, Flask, Ruby-on-Rails to mention a few. And all this zoo of applications can co-exist on the same server! What makes HostPresto! a great choice for any developer.

Originally published at https://hostpresto.com.

--

--

No responses yet