Skip to content

Python

Python logo

Welcome to the Grader Than Python project ideas page! Python is a versatile and popular programming language that is widely used in web development, scientific computing, data analysis, and machine learning. With its simple syntax and extensive libraries, Python has become a favorite among developers of all levels. In this page, we have compiled a list of Python project ideas and directions for popular and well-known development frameworks, tools, and APIs. Whether you are a beginner or an experienced developer, you'll find plenty of inspiration to create your next project using Python. So, let's dive in and explore the world of Python!,

  • Tkinter


    Create an application with graphics and buttons in just 15 minutes

    Getting started

  • FastAPI


    Build a very fast high performance HTTP REST API in 20 minutes

    Getting started

  • Django


    Create an awesome note-taking web app with a popular framework

    Getting started

Tkinter

Tkinter is a Python library that provides a way to create graphical user interfaces (GUIs) in Python. It is a standard library that is included with Python, so no additional installation is necessary. Tkinter is built on top of the Tcl/Tk GUI toolkit, which provides a cross-platform GUI development environment.

The Desktop in the Greater Than Workspace provides a graphical interface to manage files and tools, which is beneficial when working with GUI frameworks like Tkinter. It allows you to easily see the running GUI application and interact with it in real-time. The desktop also provides a window manager to switch between open windows in your application. This helps streamline the GUI development process and improve productivity.

What will we learn?

In this tutorial we will create a simple GUI calculator application built with python tkinter that is able to add, subtract multiple and divide.

download icon download icon Download complete source file

Step 1: Import the necessary modules

To get started, you need to import the necessary modules. In this case, you'll need the Tkinter module which is used for creating GUIs in Python. You can also import the messagebox module from tkinter to display error messages if needed.

Import tkinter module
from tkinter import *
from tkinter import messagebox

Step 2: Create the calculator window

Now that you have imported the necessary modules, you can create the calculator window using the Tkinter class. You can set the title of the window and its dimensions using the title() and minsize() methods.

Create the calculator window
root = Tk() # (1)!
root.title("Simple Calculator") # (2)!
root.minsize(250, 400) # (3)!
  1. Creates the main window for the calculator
  2. Sets the title of the window to "Simple Calculator"
  3. Sets the minimum size of the window to 250x400 pixels

Step 3: Create the display widget

The next step is to create the widget where the calculator's input and output will be displayed. In this example, we'll use an Entry widget to display the input and output.

Create the display widget
display = Entry(root, width=35, borderwidth=5) # (1)!
display.grid(row=0, column=0, columnspan=4, padx=10, pady=10 , sticky='ew') # (2)!
  1. Creates the display (Text box) for the calculator
  2. Places the display on the window grid

Step 4: Define the button functions

The next step is to define the functions for each button. In this example, we'll define functions for the number buttons, the clear button, the addition button, the subtraction button, the multiplication button, and the division button.

Define the button functions
def button_click(number): # (1)!
    """
    Update the display with the pressed button number.

    Parameters:
        number (int): The number to be added to the display.
    """
    current = display.get()
    display.delete(0, END)
    display.insert(0, str(current) + str(number))

def button_add(): # (2)!
    """
    Store the first number, set the math operation to addition, and clear the display.
    """
    first_number = display.get()
    global f_num
    global math_operation
    math_operation = "addition"
    f_num = int(first_number)
    display.delete(0, END)

def button_equal(): # (3)!
    """
    Perform the selected math operation and update the display with the result.
    """
    second_number = display.get()
    display.delete(0, END)

    if math_operation == "addition":
        display.insert(0, f_num + int(second_number))

    if math_operation == "subtraction":
        display.insert(0, f_num - int(second_number))

    if math_operation == "multiplication":
        display.insert(0, f_num * int(second_number))

    if math_operation == "division":
        try:
            display.insert(0, f_num / int(second_number))
        except ZeroDivisionError:
            messagebox.showerror("Error", "Cannot divide by zero")

def button_clear(): # (4)!
    """
    Clear the display.
    """
    display.delete(0, END)

def button_subtract(): # (5)!
    """
    Store the first number, set the math operation to subtraction, and clear the display.
    """
    first_number = display.get()
    global f_num
    global math_operation
    math_operation = "subtraction"
    f_num = int(first_number)
    display.delete(0, END)

def button_multiply(): # (6)!
    """
    Store the first number, set the math operation to multiplication, and clear the display.
    """
    first_number = display.get()
    global f_num
    global math_operation
    math_operation = "multiplication"
    f_num = int(first_number)
    display.delete(0, END)

def button_divide(): # (7)!
    """
    Store the first number, set the math operation to division, and clear the display.
    """
    first_number = display.get()
    global f_num
    global math_operation
    math_operation = "division"
    f_num = int(first_number)
    display.delete(0, END)
  1. This function to handles numeric button clicks and updates the display with the numbers
  2. This function to handles the addition calculations
  3. This function to handles computes the math equation
  4. This function clears the inputted values
  5. This function to handles the subtraction calculations
  6. This function to handles multiplication calculations
  7. This function to handles division calculations

Step 5: Create the button widgets

Now it's time to create the button widgets for the calculator. You can use the Button() method to create the buttons and specify their text, dimensions, and functions.

Create the buttons
number_buttons = [] # (1)!

for label in range(10): # (2)!
    button = Button( # (3)!
            root, 
            text=label, 
            padx=40, 
            pady=20, 
            command=lambda num=label: button_click(num)
        )

    if label == 0: # (4)!
        button.grid(row=4, column=0, sticky='ew')
    else: # (5)!
        number_buttons.append(button)
        row = (label - 1) // 3 + 1
        column = (label - 1) % 3
        number_buttons[-1].grid(row=row, column=column, sticky='ew')

button_add = Button(root, text="+", padx=40, pady=20, command=button_add)
button_equal = Button(root, text="=", padx=40, pady=20, command=button_equal)
button_clear = Button(root, text="Clear", padx=40, pady=20, command=button_clear)
button_subtract = Button(root, text="-", padx=40, pady=20, command=button_subtract)
button_multiply = Button(root, text="*", padx=40, pady=20, command=button_multiply)
button_divide = Button(root, text="/", padx=40, pady=20, command=button_divide)
  1. Create a list to store the number buttons
  2. Loop through the number labels and create a button for each number
  3. Create the button with the corresponding label and command
  4. If the button is zero we want to add it to the bottom of the window
  5. Add the button to the list of number buttons and place it on the calculator window

Step 6: Add the buttons to the calculator window

Finally, you can add the buttons to the calculator window using the grid() method.

Add the buttons to the window
button_clear.grid(row=4, column=1, columnspan=2, sticky='ew')
button_add.grid(row=5, column=0, sticky='ew')
button_equal.grid(row=5, column=1, columnspan=2, sticky='ew')

button_subtract.grid(row=6, column=0, sticky='ew')
button_multiply.grid(row=6, column=1, sticky='ew')
button_divide.grid(row=6, column=2, sticky='ew')

Step 7: Run the program

Now that you have completed the code, you can run the program by calling the mainloop() method on the root object.

Run the application
root.mainloop()

That's it! You have created a simple calculator using Python Tkinter.

Run the application by clicking the play button run icon run icon in the top right corner of the screen.

You can modify the code and add more functionality to the calculator to make it more advanced.


FastAPI

FastAPI is a Python web framework designed for building APIs quickly and easily. With its modern, high-performance design, FastAPI is one of the fastest Python web frameworks available, making it ideal for high-performance applications. FastAPI also offers built-in support for data validation and documentation, making it easy to create clean and well-documented APIs. Whether you're building microservices, web applications, or something else entirely, FastAPI is a powerful tool for any developer looking to build APIs quickly and efficiently.

video icon video icon Check out our FastAPI webinar recording.

What is an API?

API stands for "Application Programming Interface". In simple terms, an API is a set of protocols, routines, and tools that allow different software applications to communicate with each other. APIs enable developers to create powerful and flexible software by allowing them to integrate different services and functionalities.

What will we learn?

In this tutorial, we'll be building a simple notetaking API using FastAPI. We'll start by setting up a FastAPI instance and defining a Pydantic model to validate incoming POST requests. We'll then create a POST endpoint to accept user note information and save it to a file. Finally, we'll create a GET endpoint to retrieve a specific note using the note's title. By the end of this tutorial, you'll have a basic understanding of how to build a FastAPI API that can handle POST requests to create notes and GET requests with URL arguments to retrieve specific notes.

download icon download icon Download complete source file

Set up

In this section we will set up our development environment, so we can start developing our web API.

  1. Install the necessary packages. The first step is to install FastAPI, uvicorn, and pydantic. These are the main tools we'll be using to build and run our API. Open the terminal in your Grader Than workspace and run the following command.

    pip install fastapi uvicorn pydantic
    
  2. Next, create a file named main.py in the root directory of your workspace. From now on we will place all our code in this file.

  3. We need to import the necessary modules that we'll be using to build our API. We'll need to import FastAPI, BaseModel from Pydantic for data validation, json to save our notes to a file, and Optional from typing to define optional parameters.

    main.py
    import json
    from typing import Optional
    
    from fastapi import FastAPI
    from pydantic import BaseModel
    
  4. We'll now create a FastAPI instance that we'll use to define our API endpoints.

    main.py
    app = FastAPI()
    

Model - Pydantic

In this section we will define the structure of the data used in our application.

  1. We'll define a Pydantic model that we'll use to validate incoming POST requests. This model will require a title and content for the note.

    main.py
    class NoteCreate(BaseModel):
        title: str
        content: str
    

Logic - Handling requests

In this section we will create the code needed to handle the business logic of our application. Specifically we will create the code that will handle user requests and CRUD.

What does CRUD mean?

CRUD stands for Create, Read, Update, and Delete. It is an acronym that represents the four basic operations performed on data in a database or application. CRUD operations are fundamental to building and managing data-driven applications, allowing users to add, view, modify, and remove information as needed.

  1. Here we'll create a POST endpoint that accepts NoteCreate objects and saves them to a file.

    main.py
    @app.post("/notes/")
    async def create_note(note: NoteCreate):
        with open("notes.txt", "a+") as f:
            f.write(json.dumps(note.dict()) + "\n")
        return {"status": "Note created"}
    
  2. Finally, we'll create a GET endpoint that receives a note "title" from the user. It will then read the file containing the saved notes and return the note with the matching "title".

    main.py
    @app.get("/notes/{title}")
    async def read_note(title: str):
        with open("notes.txt", "r") as f:
            for note in f.readlines():
                note_dict = json.loads(note)
                if note_dict["title"] == note_id:
                    return note_dict
        return {"status": "Note not found"}
    

Run the server

  1. We can now start the API server using uvicorn. We'll use the --reload flag to automatically reload the server when changes are made to the code. Open the terminal in your Grader Than workspace and run the following command.

    uvicorn main:app --reload
    
  2. Access the server

    There are two ways to access the server, via the terminal and via the browser. When you use the browser you may only retrieve the notes you cannot save notes.

    We will use the curl command in the Grader Than Workspace terminal to communicate with our API.

    What is curl?

    Curl is a command-line tool used to transfer data to or from a server, using one of the supported protocols such as HTTP, HTTPS, FTP, FTPS, and many others. It allows users to send and receive data over the internet via the command line, making it a useful tool for testing and debugging web applications.

    Send a POST request to create a note

    We can test our API by sending a POST request to the /notes/ endpoint using curl or a similar tool. We'll specify the title and content of the note in the request body.

    curl -X POST "http://localhost:8000/notes/" -H "Content-Type: application/json" -d '{"title": "joke", "content": "What do you call a bear with no teeth? A gummy bear"}'
    

    Send a GET request to retrieve a specific note

    We can also retrieve a specific note using its title by sending a GET request to the /notes/{title} endpoint, replacing {title} with the title of the note we want to retrieve. In the command below we will retrieve the joke we created above.

    curl http://localhost:8000/notes/joke
    

    Let's access the workspace using the Grader Than IDE's built-in browser.

    You can only save notes with the terminal

    You must use the terminal to save notes because the terminal is the only way you can make POST requests to your API.

    1. Open the command pallet in your Grader Than IDE by pressing the keys below at the same time:

      Cmd+Shift+P

      Ctrl+Shift+P

      Ctrl+Shift+P

    2. Now that the command pallet is open type > simple browser show and press Enter

    3. Copy and paste your workspace's url into the text field that appears. Replace the text ide at the beginning of the url with 8000 and replace the path after graderthan.com with /notes/{title}.

      Example: https://8000-wss-{workspace-id}.workspace.graderthan.com/notes/joke (1)

      1. The {workspace-id} is your workspace's unique identifier.

      In this example we are accessing the joke we created with the POST request in the terminal section.


Django

Django is a high-level, open-source Python web framework that encourages rapid development and clean, pragmatic design. It follows the Model-View-Template (MVT) architectural pattern and provides a collection of tools and libraries to build scalable and maintainable web applications efficiently.

video icon video icon Check out our Django webinar recording.

Developers turn to Django because it simplifies common web development tasks, such as handling user authentication, form handling, and database operations, allowing developers to focus on writing their application logic without getting bogged down in low-level details.

What will we learn?

In this tutorial, we will create a simple note-taking application using Python, Django, SQLite, Bootstrap5, and Django Crispy Forms. By following these steps, you will learn how to create a web application that allows users to create, edit, and delete notes.

Set up

By the end of this section you will be able to run your Django server and connect to it from the web browser.

  1. Install the dependencies

    In this step we will install a set of external software packages we will use to build our web app.

    1. Create a file named requirements.txt in your project's root directory and copy and paste the following text into it.

      # Core dependancies
      django>=4.1.7,<5.0.0
      
      # User interface dependancies
      django-crispy-forms>=2.0,<3.0
      crispy-bootstrap5>=0.7,<1.0
      django-bootstrap-v5>=1.0.11,<2.0.0
      
    2. Now open your terminal and run the following command to install all the dependencies listed in the requirements.txt file.

      pip install -r requirements.txt
      
    What are these dependencies?
    Dependency Description
    django The core Django framework, which provides tools and libraries for building web applications in Python.
    django-bootstrap-v5 A package that makes it easy to include Bootstrap, a popular front-end framework, in a Django project. Bootstrap provides a set of pre-built CSS and JavaScript components for responsive design, typography, forms, navigation, and other common web elements.
    django-crispy-forms A Django app that helps to create DRY, reusable, and elegant forms using Bootstrap styling. It simplifies the process of rendering form fields with proper CSS classes and structure.
    crispy-bootstrap5 A package that augments the django-crispy-forms dependency by adding support for the new Bootstrap 5 framework.
    Why don't we list the dependencies in a single pip install command?

    This approach is beneficial for:

    • Version control: It makes tracking and updating dependency versions easier.

    • Collaboration: Team members can easily set up their environments with the correct dependencies.

    • Deployment: It ensures the production environment uses the same dependency versions as the development environment.

  2. Create a Django project

    The Django project is where your Django application code will be saved.

    Create a new Django project called note_app, by running the following command:

    django-admin startproject note_app
    

    Run the following command to change the directory of your terminal to the newly created note_app directory:

    cd note_app
    
  3. Create a Django app

    In Django, an app is a self-contained module that encapsulates a specific functionality of a web application.

    Using the same terminal as before, create a new Django app called notes:

    python manage.py startapp notes
    
  4. Set up the settings note_app/settings.py file

    1. Open the note_app/settings.py file and replace the ALLOWED_HOST variable with the following code:

      ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '.workspace.graderthan.com']
      

      This will enable you to connect to a Django server hosted on your Grader Than Workspace using your unique workspace URL.

    2. Add crispy_forms, crispy_bootstrap5, bootstrap5 and notes to the INSTALLED_APPS list in the note_app/settings.py file at roughly line 33:

      INSTALLED_APPS = [
          ...
          "crispy_forms",
          "crispy_bootstrap5",
          "bootstrap5",
          "notes",
      ]
      
    3. Add the CRISPY_TEMPLATE_PACK and CRISPY_ALLOWED_TEMPLATE_PACKS variables to the bottom of your note_app/settings.py file:

      CRISPY_TEMPLATE_PACK = "bootstrap5"
      
      CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
      
    4. Add the CSRF_TRUSTED_ORIGINS variable to the bottom of your note_app/settings.py file:

      CSRF_TRUSTED_ORIGINS = ['https://*.workspace.graderthan.com']
      
      Learn more about CSRF

      CSRF, or Cross-Site Request Forgery, is a type of web security vulnerability where an attacker tricks a user into performing unintended actions on a web application while the user is authenticated. The attacker leverages the user's privileges, and the web application is unable to differentiate between the forged request and a legitimate one.

      Django has built-in protection against CSRF attacks by using CSRF tokens. A CSRF token is a unique, random value that is generated and sent to the client, typically in the form of a hidden input field within a form. When the form is submitted, the server checks if the token matches the one stored in the user's session, ensuring the request is legitimate.

      CSRF_TRUSTED_ORIGINS is a Django setting used when your application needs to accept cross-origin requests (requests from different domains). By default, Django only accepts same-origin requests to prevent CSRF attacks. However, when you need to allow cross-origin requests, you must define a list of trusted origins in CSRF_TRUSTED_ORIGINS. This setting tells Django which origins (domains) are considered safe for accepting requests and should be exempt from the same-origin check.

    5. Allow viewing from the Grader Than IDE. Add the following lines of code to the bottom of your note_app/settings.py file.

      if DEBUG:
          MIDDLEWARE.remove("django.middleware.clickjacking.XFrameOptionsMiddleware")
      

      This will remove the XFrameOptionsMiddleware middleware from your app server when it's running in DEBUG mode. You need to remove this in order to quickly view your web app from the simple browser built into the Grader Than IDE.

      The middleware is only removed during DEBUG mode because it poses a security risk when running without it in production. Read more about the security risks below.

      Security Risk

      django.middleware.clickjacking.XFrameOptionsMiddleware is a middleware in Django that helps protect your web application from clickjacking attacks. Clickjacking is a malicious technique in which an attacker embeds a transparent or disguised element (e.g., a button) within an iframe on their website, tricking users into clicking it while they interact with the visible content.

      The XFrameOptionsMiddleware adds the X-Frame-Options header to the HTTP response, which instructs the browser whether the content can be embedded within an iframe. The header can be set to values like 'DENY' (disallowing embedding) or 'SAMEORIGIN' (allowing embedding only from the same domain).

      Including this middleware helps enhance the security of your web application by mitigating the risk of clickjacking attacks, ensuring that your content is not embedded in unauthorized locations.

    You are done setting up your development environment. You are now ready to start adding your code.

Models - Data and Forms

In this section you will create a framework for your data management. All data will be saved in a SQL database, the wonderful thing about Django is you don't need to know any SQL to complete this task.

  1. Create the Note model

    In the notes/models.pyfile add the following Note model code:

    from django.db import models
    
    class Note(models.Model):
        title = models.CharField(max_length=200)
        content = models.TextField()
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)
    
        def __str__(self):
            return self.title
    
    What is a model?

    A model in Django is a Python class that represents a database table and defines the structure of the data to be stored. It inherits from django.db.models.Model and serves as an abstraction layer between the application logic and the underlying database. Each attribute of the model class corresponds to a field in the table, defining its data type and constraints. Models also include methods to interact with the database, such as querying, creating, updating, and deleting records.

    Django uses an Object-Relational Mapping (ORM) system to translate between the model classes and the actual database tables, allowing developers to work with databases using Python objects and methods rather than writing raw SQL queries.

  2. Create the Note form

    This is the programmatic representation of the HTML form that will allow the user to create and edit notes. This will automatically handle the database SQL saving and loading transactions for us.

    Create a file named notes/forms.py. Then put the following code within the newly created file:

    from crispy_forms.helper import FormHelper
    from crispy_forms.layout import Submit
    from django import forms
    from .models import Note
    
    class NoteForm(forms.ModelForm):
        class Meta:
            model = Note
            fields = ['title', 'content']
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.helper = FormHelper()
            self.helper.form_method = 'post'
            self.helper.add_input(Submit('submit', 'Save note'))
    
  3. Set up the database

    Create and apply the database migrations by running the following commands in your terminal:

    python manage.py makemigrations
    
    python manage.py migrate
    

    The result of the command should look similar to the output displayed below:

    ❯ python manage.py makemigrations
    Migrations for 'notes':
    notes/migrations/0001_initial.py
        - Create model Note
    ❯ python manage.py migrate
    Operations to perform:
        Apply all migrations: admin, auth, contenttypes, notes, sessions
        Running migrations:
        Applying contenttypes.0001_initial... OK
        Applying auth.0001_initial... OK
        Applying admin.0001_initial... OK
        Applying admin.0002_logentry_remove_auto_add... OK
        ...
        Applying auth.0011_update_proxy_permissions... OK
        Applying auth.0012_alter_user_first_name_max_length... OK
        Applying notes.0001_initial... OK
        Applying sessions.0001_initial... OK
    

    Database migrations are a way to manage changes to the database schema over time, such as creating new tables, altering existing tables, or adding new columns. They represent a set of instructions that describe how to evolve the database from one state to another. In Django, migrations are generated automatically based on the changes made to the models.

    Why do we use database migrations?

    Migrations are essential for several reasons:

    • Consistency: Migrations ensure that the database schema stays consistent across different environments, such as development, staging, and production.

    • Collaboration: When working in a team, migrations help synchronize the database schema among team members as they modify models independently.

    • Version control: Migrations serve as a version control system for the database schema, allowing you to track changes and revert to a previous state if necessary.

    • Data integrity: Applying migrations helps preserve data integrity by handling the transformation of data when altering the schema, like adding default values or converting data types.

Your web app's data is properly structured. You are now ready to create the backend logic and user interface of your application.

Views - Logic and Routing

In this section we will create the CRUD of your application. By the end of this section your web app will have URL endpoints that users will use to send and receive note data and display your web pages.

  1. Open the notes/views.py file. Next create the CRUD views for the Note model by adding the following code to the notes/views.py file:

    notes/views.py
    from django.shortcuts import render, redirect, get_object_or_404
    from .models import Note
    from .forms import NoteForm
    
    def note_list(request):
        """
        Renders a list of all notes in the database.
    
        Args:
            request (HttpRequest): The incoming request from the user.
    
        Returns:
            HttpResponse: A rendered HTML page displaying the list of notes.
        """
        notes = Note.objects.all()
        return render(request, 'notes/note_list.html', {'notes': notes})
    
    def note_create(request):
        """
        Handles the creation of a new note.
    
        Args:
            request (HttpRequest): The incoming request from the user.
    
        Returns:
            HttpResponse: A rendered HTML page with the note creation form.
                        On successful form submission, redirects to the note list page.
        """
        form = NoteForm(request.POST or None)
        if form.is_valid():
            form.save()
            return redirect('notes:note_list')
        return render(request, 'notes/note_form.html', {'form': form})
    
    def note_edit(request, pk):
        """
        Handles the editing of an existing note.
    
        Args:
            request (HttpRequest): The incoming request from the user.
            pk (int): The primary key of the note to be edited.
    
        Returns:
            HttpResponse: A rendered HTML page with the note edit form.
                        On successful form submission, redirects to the note list page.
        """
        note = get_object_or_404(Note, pk=pk)
        form = NoteForm(request.POST or None, instance=note)
        if form.is_valid():
            form.save()
            return redirect('notes:note_list')
        return render(request, 'notes/note_form.html', {'form': form})
    
    def note_delete(request, pk):
        """
        Handles the deletion of a note.
    
        Args:
            request (HttpRequest): The incoming request from the user.
            pk (int): The primary key of the note to be deleted.
    
        Returns:
            HttpResponse: A rendered HTML page for confirming the note deletion.
                        On successful deletion, redirects to the note list page.
        """
        note = get_object_or_404(Note, pk=pk)
        if request.method == 'POST':
            note.delete()
            return redirect('notes:note_list')
        return render(request, 'notes/note_confirm_delete.html', {'note': note})
    
    What does CRUD mean?

    CRUD stands for Create, Read, Update, and Delete. It is an acronym that represents the four basic operations performed on data in a database or application. CRUD operations are fundamental to building and managing data-driven applications, allowing users to add, view, modify, and remove information as needed.

  2. Now let's create URL routes that will tell Django where to direct requests based on the URL paths.

    Create a file named notes/urls.py, add the following code to the new file:

    from django.urls import path
    from . import views
    
    app_name = "notes"
    
    urlpatterns = [
        path('', views.note_list, name='note_list'),
        path('new/', views.note_create, name='note_create'),
        path('<int:pk>/edit/', views.note_edit, name='note_edit'),
        path('<int:pk>/delete/', views.note_delete, name='note_delete'),
    ]
    

    Open the note_app/urls.py file and add the following paths to the urlpatterns list:

    from django.urls import path, include
    from django.views.generic.base import RedirectView
    
    urlpatterns = [
        ...
        path('', RedirectView.as_view(pattern_name='notes:note_list')),
        path('notes/', include('notes.urls')),
    ]
    

Now your application's business logic is complete. It's time to create the HTML templates your users will use when interacting with your note-taking app.

Templates - HTML/CSS

In this section we will create our templates. A template is a text file that defines the structure and layout of an HTML page. It can include placeholders, logic, and control structures to dynamically generate content based on the context provided by the view.

Django is awesome, it comes with its own template language, which is designed to be simple, flexible, and safe to use for non-programmers.

  1. Create the notes/templates/notes/. We will put all of our note's templates in this directory.

    Inside the newly created notes/templates/notes/ directory create the files discussed below. By the end of this section your project should resemble the following file system structure.

    ├── .venv
    └── note_app
        ├── note_app
        ├── manage.py
        ├── note_app
        └── notes
            ├── admin.py
            ├── apps.py
            ├── forms.py
            ├── __init__.py
            ├── migrations
            ├── models.py
            └── templates
                └── notes
                    ├── note_confirm_delete.html
                    ├── note_form.html
                    └── note_list.html
    
  2. Create a file named note_list.html in the notes/templates/notes/ directory and add the following code to it. This will render the web page that displays all the created notes.

    note_list.html

    notes/templates/notes/note_list.html

    {% load crispy_forms_tags %}
    
    <!DOCTYPE html>
    <html>
    <head>
        <title>Note Taking App</title>
        {% load bootstrap5 %}
        {% bootstrap_css %}
        {% bootstrap_javascript %}
    </head>
    <body>
    <div class="container">
        <h1>Note List</h1>
        <div class="d-grid gap-2">
        <a href="{% url 'notes:note_create' %}" class="btn btn-primary">Create Note</a>
        </div>
        <hr>
            {% for note in notes %}
            <div class="card mb-2">
                <div class="card-body">
                    <h5 class="card-title">{{ note.title }}</h5>
                    <p class="card-text">{{ note.content|truncatechars:32 }}</p>
                    <div class="btn-group small" role="group" aria-label="Basic mixed styles example">
                        <a href="{% url 'notes:note_edit' note.pk %}" class="btn btn-outline-success btn-sm">Edit</a>
                        <a href="{% url 'notes:note_delete' note.pk %}" class="btn btn-outline-danger btn-sm">Delete</a>
                    </div>
                </div>
            </div>
            {% empty %}
                <h2>No notes available.</h2>
            {% endfor %}
    </div>
    </body>
    </html>
    
  3. Create a file named note_form.html in the notes/templates/notes/ directory and add the following code to it. This will render the web page that enables a user to create or edit a note.

    note_form.html

    notes/templates/notes/note_form.html

    {% load crispy_forms_tags %}
    
    <!DOCTYPE html>
    <html>
    <head>
        <title>Note Taking App</title>
        {% load bootstrap5 %}
        {% bootstrap_css %}
        {% bootstrap_javascript %}
    </head>
    <body>
    <div class="container">
        <h1>{% if form.instance.pk %}Edit{% else %}Create{% endif %} Note</h1>
        <form method="post">
            {% csrf_token %}
            {{ form|crispy }}
            <button type="submit" class="btn btn-primary">Save</button>
            <a href="{% url 'notes:note_list' %}" class="btn btn-secondary">Cancel</a>
        </form>
    </div>
    </body>
    </html>
    
  4. Create a file named note_confirm_delete.html in the notes/templates/notes/ directory and add the following code to it. This page is used to double-check if a user wants to delete a note.

    note_confirm_delete.html

    notes/templates/notes/note_confirm_delete.html

    {% load crispy_forms_tags %}
    
    <!DOCTYPE html>
    <html>
        <head>
            <title>Note Taking App</title>
            {% load bootstrap5 %}
            {% bootstrap_css %}
            {% bootstrap_javascript %}
        </head>
        <body>
        <div class="container">
            <h1>Delete Note</h1>
            <p>Are you sure you want to delete "{{ note.title }}"?</p>
            <form method="post">
                {% csrf_token %}
                <button type="submit" class="btn btn-danger">Yes, delete</button>
                <a href="{% url 'notes:note_list' %}" class="btn btn-secondary">No, cancel</a>
            </form>
        </div>
        </body>
    </html>
    

Run the server

Your work is done, you've created a web app with Django. Now it's time to run the server and view the results!

Start the server by running the following command:

python manage.py runserver
  1. Open the command pallet in your Grader Than IDE by pressing the keys below at the same time:

    Cmd+Shift+P

    Ctrl+Shift+P

    Ctrl+Shift+P

  2. Now that the command pallet is open type > simple browser show and press Enter

  3. Copy and paste your workspace's url into the text field that appears. Replace the text ide at the beginning of the url with 8000 and replace the path after graderthan.com with /.

    Example: https://8000-{workspace-id}.workspace.graderthan.com/ (1)

    1. The {workspace-id} is your workspace's unique identifier.

    This will take you to the notes list page of your Django application.

  1. Copy your workspace url.

  2. Create a new browser tab.

  3. Paste your workspace url into the new browser tab. Replace the text ide at the beginning of the url with 8000 and replace the path after graderthan.com with /.

    Example: https://8000-{workspace-id}.workspace.graderthan.com/ (1)

    1. The {workspace-id} is your workspace's unique identifier.

    This will take you to the notes list page of your Django application.

Django automatically updates

The Django server automatically updates with the changes you make. This means most of the edits you make to your python files or HTML templates will automatically be reflected in your running web app. Just refresh the web page to see the changes.

Make sure you migrate your DB changes

When you make an edit to the database models make sure you first stop the server. Then run the makemigrations command and then the migrate command. Start the server again to see the changes.