Learn to Code via Tutorials on Repl.it

← Back to all posts
Learning Web Development w/ Python Part 3
ArchieMaclean (668)

Learning Web Development with Python and Django

Part 3

Thank you to @timmy_i_chen and @masfrost for sorting out the repl.it issue!

Welcome!

In Part 1 and Part 2 we learned how to use views and templates to create some basic pages on our web app.
In the rest of the series, we will be creating our own Web Forum app, that allows users to post questions and other users to answer them.
In this tutorial we will first cover how to split our large app into smaller apps, and then we will set up an external database for storing information.

A New Basic Template

In the previous parts, I have given you a basic Django template to start work with. However, this template is fairly limiting because it does not allow access to the command line. From now on, we will be using another template, which you can find here. This also fixes some other bugs that mean that normal Django repls cannot use external databases.
Fork the repl, rename it to something like Web Forum, and let's begin!

Running the repl

Before, when using Django, we just had to click the run button in order to run. Now, we are presented with a prompt. To run the server, just press enter without typing anything, and you should get our familiar startup screen:


Now we're ready to start.

Apps

So far, when creating our (very basic) websites, all of our files have been in the one folder - main. However, when you are running a large or complicated website, this can get very confusing and hard to work with. To fix this, Django has a built-in startapp function, that maks separating your code into separate apps very easy.

For example, an online shop may have an app for:

  • Users - deals with logging on, password reset, e.t.c.
  • Shopping Cart - deals with adding/removing products from the cart.
  • Products - deals with displaying/updating products.

The only problem is that startapp doesn't work with repl.it.

DIY startapp

Fortunately, all the startapp command does is create some folders and write a minimal amount of code, so we can do the same fairly quickly. We are creating a web forum, so let's create an app called 'Posts'.

  • Create a folder (at the top level, i.e. outside the main folder) called Posts
  • Within Posts, create empty files for each of the following:
    • __init__.py (2 underscores on either side of the init)
    • admin.py
    • apps.py
    • models.py
    • tests.py
    • views.py
  • Next, create a folder called migrations
    • Within migrations, add a file called __init__.py (2 underscores on either side of the init)

The sidebar on your project should now look like this:

(Or similar with the light theme)

Now we need to add just a little bit of code.
To apps.py add the following code:

from django.apps import AppConfig

class PostsAppConfig(AppConfig):
  name = 'Posts'

You don't really need to know how this code works - basically all it does is create a configuration class to allow the app to be used by Django.

Updating settings.py

After you have created the app, you need to update the settings.py file in order for Django to be able to find the app. To do this, go to settings.py and change the INSTALLED_APPS list.

INSTALLED_APPS = [

    # stuff

    'Posts.apps.PostsAppConfig',
    'main',
]

This links to the code that we put in apps.py above.


Pages within Apps

Now we have made our app! Let's make a home page within the app.

Template

First, we create folder called templates, then add a file called base.html into that folder. This will be our base template. Add the following html to base.html:

<!DOCTYPE html>
<html>
  <head>
    <title>{% block title %}{% endblock title %}</title>
  </head>
  <body>
    <nav>
      This will be the navbar.
    </nav>
    <div id="content">
      {% block content %}
      {% endblock content %}
    </div>
  </body>
</html>

You should be familiar with most of this - the only bits I haven't covered before are:

  • nav - this is a html navigation bar element.
  • div - this is a html element that surrounds a distinct area in the html.
    These will be needed because we will be using CSS later to apply styles to different sections of the page.

Next, create a file called home.html, and the following html:

{% extends 'base.html' %}

{% block title %}Home{% endblock title %}

{% block content %}
<h1>Home</h1>
<p>Welcome to the home page!</p>
{% endblock content %}

You should be comfortable with this - if you don't understand the {% %} tags, then look back at Part 2.

View

Now we need to create our view.
In Posts/views.py, add the following code:

from django.views.generic import TemplateView

class HomePageView(TemplateView):
  template_name='home.html'

This is just a basic class-based view that will display the template that we created above.

URL

Finally, we need to map a URL to our view. This is slightly more complicated because our page is within the Posts app, but urls.py is in main. How do we solve this? The answer is that we create another urls.py file within Posts, then redirect the main urls.py to this file. Sounds complicated? It is actually quite simple - let's do it.
Within Posts, create a file called urls.py, and add the following code:

from django.urls import path
from .views import HomePageView

urlpatterns = [
  path('', HomePageView.as_view(), name='home'),
]

This is fairly simple to understand: the URL '' (i.e. no URL) gives the home page - so if the domain was https://example.domain.com, then the home page would be located at https://example.domain.com/.

Next, in main/urls.py, change the file to this:

from django.urls import path, include    # include has been added
from django.contrib import admin

urlpatterns = [
  path('admin/', admin.site.urls),
  path('',include('Posts.urls')),       # this has also been added
]

What does this do? We are importing the include function - this is used for redirecting to another file. So the new line we added just tells Django to check the Posts.urls file (that we created above).

What about the first ''? This can be confusing, but for example, if we changed the line to

path('hello/',include('Posts.urls')),

Then all the URLs in our Posts/urls.py file would be located at https://example.domain.com/hello/... . We will use this later - all of our user URLs will be located at https://example.domain.com/accounts/...

If you run the program now (by running the repl and pressing enter without typing anything in), you will see that our home page is where it should be!

url vs path

You may have noticed that the last time we used Django URLs, we have a list of urls - like this:

urlpatterns = [
  url('',blah),
  url('about',blah),
]

whereas now we are using path instead. path is the new version of url.
path is better because it doesn't use regex which can be confusing for beginners, and it also makes writing some URLs easier and makes them more readable - especially for database-driven pages.


Databases

Databases are a way of storing data in a way that can be accessed easily, encrypted easily and changed easily.
Django usually uses sqlite3 databases by default - in fact, if you look in your file list at the side, you will see Django has automatically created a file called db.sqlite3. However, repl.it doesn't support databases - if you refresh your page, all your data is lost. For this reason, we are going to use an external database.

Setting up our Database

Now we are going to set up our external database. We will be using postgresql, because it is widely used and we can use it for free. We will be using ElephantSQL to host our database.
First, create an account here.
Once you have done that, you should be faced with the following page:

Click on Create a new Instance and follow through all the instructions. You can just use a Tiny Turtle instance because it is free.
You will be asked to select a region - just pick somewhere near you.

Once you've done that, you will be redirected back to the instances page. Click on the instance that you just created and you should get a page like this:

(I've just greyed out the password so you aren't tempted to use my database and corrupt everything.)
Now that the database host is ready, we can set up the database on Django!

Go to settings.py and you will see a list called DATABASES. Change the list to look like this:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'Default Database',
        'USER': 'User',
        'PASSWORD': 'Password',
        'HOST': 'Server',
        'PORT': ''
    }
}

Swap the text for the correct data that was given for the instance. For the server, you don't need the bit in brackets - so for my database, I can just set the server to manny.db.elephantsql.com.
If you run this now, you get a long error:

This is because Django was expecting there to be some default tables in the database. To fix this, instead of pressing enter at the command line, type the following:

> python manage.py migrate

This applies the changes to the database that Django wants there to be.

And that's the database set up! If you run the server now (by just pressing enter), then it runs correctly and our home page is displayed!

Conclusion

Now that we have set up our database, we're ready to create some database-driven web pages! In Part 4 we will learn how to use databases with Django.

Please upvote if you found this tutorial helpful, it supports me and lets me know that you want more! If you have any questions, post in the comments and I (or someone else) will answer them.

Commentshotnewtop
AS4 (3)

https://repl.it/@AS4/Django-Template-1. I get error

Traceback (most recent call last):
  File "/home/runner/.local/lib/python3.6/site-packages/django/db/utils.py", line 110, in load_backend
    return import_module('%s.base' % backend_name)
  File "/usr/local/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 978, in _gcd_import
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 936, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 978, in _gcd_import
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 936, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 978, in _gcd_import
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 936, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 978, in _gcd_import
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 936, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 978, in _gcd_import
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 948, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'packy'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 18, in <module>
    execute_from_command_line(sys.argv)
  File "/home/runner/.local/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/home/runner/.local/lib/python3.6/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/runner/.local/lib/python3.6/site-packages/django/core/management/base.py", line 323, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/runner/.local/lib/python3.6/site-packages/django/core/management/base.py", line 361, in execute
    self.check()
  File "/home/runner/.local/lib/python3.6/site-packages/django/core/management/base.py", line 390, in check
    include_deployment_checks=include_deployment_checks,
  File "/home/runner/.local/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 64, in _run_checks
    issues = run_checks(tags=[Tags.database])
  File "/home/runner/.local/lib/python3.6/site-packages/django/core/checks/registry.py", line 72, in run_checks
    new_errors = check(app_configs=app_configs)
  File "/home/runner/.local/lib/python3.6/site-packages/django/core/checks/database.py", line 9, in check_database_backends
    for conn in connections.all():
  File "/home/runner/.local/lib/python3.6/site-packages/django/db/utils.py", line 216, in all
    return [self[alias] for alias in self]
  File "/home/runner/.local/lib/python3.6/site-packages/django/db/utils.py", line 216, in <listcomp>
    return [self[alias] for alias in self]
  File "/home/runner/.local/lib/python3.6/site-packages/django/db/utils.py", line 201, in __getitem__
    backend = load_backend(db['ENGINE'])
  File "/home/runner/.local/lib/python3.6/site-packages/django/db/utils.py", line 125, in load_backend
    ) from e_user
django.core.exceptions.ImproperlyConfigured: 'packy.db.elephantsql.com' isn't an available database backend.
Try using 'django.db.backends.XXX', where XXX is one of:
    'mysql', 'oracle', 'postgresql', 'sqlite3'
AS4 (3)

put new code in and;

 python manage.py migrate
  File "<stdin>", line 1
    python manage.py migrate
                ^
SyntaxError: invalid syntax
ArchieMaclean (668)

@AS4 Hi, when I have something like this:

# stuff

array = [
  # stuff

  blah,
]

I just mean to add the other code (stuff is just a placeholder so I don't have to put in the entire code).
If you change all those places, it should work :)

runcomet (0)

@ArchieMaclean hey! don't know if this is a problem but my Repl has been waking up for like 30mins now.
Part 2 went like a breeze, really good tutorial.
The new template just keeps on loading....

ArchieMaclean (668)

@runcomet Hmm, that's strange. Have you tried forking the repl? If not, can you give a link to the repl?
Thanks

ArchieMaclean (668)

@runcomet I'm glad it's working now. Sometimes repl.it web repls just seem to freeze and I don't think there's much you can do about it unfortunately, apart from refreshing or forking :|

Shkev (0)

What should I put for the name of the database, because I am constantly getting an error that says FATAL: database "[insert name]" does not exist?

ArchieMaclean (668)

@Shkev Could you give me a link to the repl? Thanks

Shkev (0)

@ArchieMaclean I figured it out. It turns out that the name of the database is the same as the user name. Thanks!

ArchieMaclean (668)

@Shkev I'm glad you figured it out and it's all working now :)

gesherLaAtid (0)

For some reason the website will not load.
This file never loaded at all, I suspect this is because I was not in the tab at the start when it was loading.

ArchieMaclean (668)

@gesherLaAtid I'm sorry, can you explain what you mean?
Which website isn't loading?

gesherLaAtid (0)

@ArchieMaclean
First of all thanks so much for the lightning quick response.
We opened the template and clicked run and all that as you instructed, and it said something to the effect of reloading or unable to connect (sorry for not knowing exactly but at this point Iexited everything) and just kept failing to connect.

Any idea why?

ArchieMaclean (668)

@gesherLaAtid Hmmm...I'm not sure if that is a problem with the actual code - it might be repl.it. Do you have a link to the repl? Thanks.

ArchieMaclean (668)

Hey Everyone
I've noticed that sometimes the new django freezes - when you run it, nothing happens. When this happens, either wait for a while, or fork the repl.
Thanks!

Itai52 (2)

I tried to run the program at the point where you said "If you run the program now (by running the repl and pressing enter without typing anything in), you will see that our home page is where it should be!" but it doesn't work. It says "ModuleNotFoundError: No module named 'Posts.views'". Any idea what to do?

Never mind, I just ran it again and it worked, no idea what happened there...

ArchieMaclean (668)

@Itai52 Hmm...Do you have a link to the repl? A lot of Django's error messages are very long - it is probably some very small thing like missing a ..

ArchieMaclean (668)

@Itai52 That's strange. Sometimes you just need to refresh or re-run the program to make sure it's up-to-date.
Glad the problem wasn't serious! :)

allanmwai (0)

@ArchieMaclean
mine mot working same problem "ModuleNotFoundError: No module named 'Posts.views......here is the link https://Posts.allanmwai.repl.run

ArchieMaclean (668)

@allanmwai Hi, I can't look in to this fully right now, but can you try this:

  • The Posts/apps.py file seems to be a bit strange, so try deleting it then creating a new file.
  • When I put a comment like this:

    you shouldn't have deleted all the other items in the list (I think there were other items in the list before that?) #stuff is just a placeholder so I don't have to write out all the stuff that's already there.

Let me know you try these both and it still doesn't work.