Skip to content

Instantly share code, notes, and snippets.

@amulifts
Last active May 3, 2023 18:34
Show Gist options
  • Save amulifts/2b3e4952e49e5cab4a29c4682e23ee3e to your computer and use it in GitHub Desktop.
Save amulifts/2b3e4952e49e5cab4a29c4682e23ee3e to your computer and use it in GitHub Desktop.
Django To Revise - Aman Khadka

Django Tutorial

This tutorial is for my personal reference.

What is Django?

Django is a web framework that allows you to easily build web applications. It is written in Python and follows the MVT architecture, which we'll discuss in just a moment. Django is a powerful tool that can help you build complex web applications quickly and easily, thanks to its built-in features and ease of use.

Main framework components

Django follows the MVT (Model-View-Template) pattern. It is a slightly similar pattern to the well-known MVC (Model-View-Controller) pattern.

MVC

  • Model - the model represents the data and business logic of the application
  • View - the view is responsible for rendering the data into a format suitable for presentation to the user
  • Controller - the controller acts as an intermediary between the model and view, handling user input and updating the model accordingly

MVT

  • Model – Defines the logical data structure and is the data handler between the database and the View.
  • View – Communicates with the database via the Model and transfers the data to the Template for viewing.
  • Template – Is the presentation layer. Django uses a plain-text template system that keeps everything that the browser renders.

The framework itself acts as the Controller. It sends a request to the appropriate view, according to the Django URL configuration.

When developing any Django project, you will always work with models, views, templates, and URLs.

The Django architecture

This shows how Django processes requests and how the request/response cycle is managed with the different main Django components: URLs, views, models, and templates:

Django Architecture

  • URLs - When a request is received by a Django application, the first component that handles it is the URL dispatcher. The URL dispatcher matches the URL in the request to a view function that will handle the request. The URL dispatcher is configured using regular expressions to match patterns in the URL.

  • Views - Once the URL dispatcher has matched the URL to a view function, the view function is called. The view function is responsible for processing the request and returning an HTTP response. The view function can perform any necessary processing, such as querying the database using models, before returning the response.

  • Models - Models are Python classes that define the structure of the database and provide an interface for querying and manipulating data. The view function can use models to query the database and retrieve data to be included in the response.

  • Templates - Templates are files that define the structure and content of the response that will be sent to the client. The view function can render a template with data retrieved from models to create the response.

In summary, the request/response cycle in Django is managed by the URL dispatcher, view functions, models, and templates. The URL dispatcher matches the URL to a view function, which processes the request and uses models to query the database. The view function then renders a template to create the response that is sent back to the client.

Django also includes hooks in the request/response process, which are called middleware. Middleware has been intentionally left out of this diagram for the sake of simplicity. For now know that, Middleware can be used to perform tasks such as authentication, logging, and caching.

Installing Python

The first thing we need to do is to install Python, which is the programming language that Django is built on. Django supports Python 3.6 or higher. You can download Python from the official website Click Here!.

Follow the installation steps and make sure to select the option to add Python to your system path.

Installing a Code Editor / IDE

The next step is to install a code editor also called IDE. A code editor is a software application that is used to write and edit code. There are many code editors available, but we recommend using Visual Studio Code (VS Code), which is a popular and powerful code editor. You can download VS Code from the official website Click Here!.

Follow the installation steps and make sure to add VS Code to your system path.

Creating a Python virtual environment

  • Verify the Python installation
python --version
  • Navigate to the directory where you want to create your virtual environment.
  • Run one of the following commands to create the virtual environment:
    • To create a virtual environment using the built-in venv module in Python 3:
    python -m venv env
    
    • To create a virtual environment using the virtualenv package:
    pip install virtualenv
    
    virtualenv env
    
  • Once the virtual environment is created, activate it by running the following command:
source env/bin/activate  (on Unix-based systems)
or
env\Scripts\activate  (on Windows systems)

  • When you are finished working in the virtual environment, deactivate it by running the following command:
deactivate

Installing Django

  • Run the following command at the shell prompt to install Django with pip:
pip install django
  • Run the following command at the shell prompt to check version:
python -m django --version

In Python, the -m option is used to run a module as a script from the command line.

Creating a Project

  • Create a new Django project using the django-admin command:
django-admin startproject project_name

Replace project_name with the name of your project.

project_name/
    manage.py
    project_name/
      __init__.py
      asgi.py
      settings.py
      urls.py
      wsgi.py

The outer project_name/ directory is the container for our project. It contains the following files:

  • manage.py - This is a command-line utility used to interact with your project.
  • project_name/ - This is the Python package for your project, which consists of the following files:
    • __init__.py: An empty file that tells Python to treat the project_name directory as a Python package.
    • asgi.py: This is the configuration to run your project as an Asynchronous Server Gateway Interface (ASGI) application with ASGI-compatible web servers. ASGI is the emerging Python standard for asynchronous web servers and applications.
    • settings.py: This indicates settings and configuration for your project and contains initial default settings.
    • urls.py: This is the place where your URL patterns live. Each URL defined here is mapped to a view.
    • wsgi.py: This is the configuration to run your project as a Web Server Gateway Interface (WSGI) application with WSGI-compatible web servers.

Note - WSGI and ASGI are both interfaces that allow web servers and Python web applications to communicate with each other. WSGI is designed for use with synchronous web servers and applications, while ASGI is designed for use with asynchronous web servers and applications.

  • Django comes with a system that helps you manage database migrations.
cd project_name
python manage.py migrate
  • By applying the initial migrations, the tables for the applications listed in the INSTALLED_APPS setting are created in the database.

Introduction to WSGI and ASGI in Django

When building a web application using Django, you will eventually need to deploy your application to a production environment. To do this, you will need to use a web server that can handle incoming requests and route them to your application.

Two commonly used interfaces for communicating between web servers and web applications are WSGI and ASGI.

What is WSGI?

WSGI stands for "Web Server Gateway Interface". It is a specification for a simple and universal interface between web servers and web applications or frameworks written in Python. WSGI was introduced as a standard in 2003 and has since become a widely adopted interface for Python web development.

In Django, the wsgi.py file provides the entry point for a WSGI-compatible web server to interact with your Django application.

When a request comes in, the web server will route the request to the wsgi.py file, which will create an instance of the Django application and return a response back to the server.

Here's an example of a wsgi.py file for a Django application:

import os
from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_wsgi_application()

In this example, we first set the DJANGO_SETTINGS_MODULE environment variable to tell Django where to find the project settings. We then create an instance of the Django application using get_wsgi_application() and assign it to the application variable.

What is ASGI?

ASGI stands for "Asynchronous Server Gateway Interface". It is a specification for a more advanced interface between web servers and web applications or frameworks written in Python. ASGI is designed to support asynchronous programming, which allows for more efficient handling of multiple simultaneous connections and long-lived connections, such as WebSockets.

In Django, the asgi.py file provides the entry point for an ASGI-compatible web server to interact with your Django application. When a request comes in, the web server will route the request to the asgi.py file, which will create an instance of the Django application and return a response back to the server.

Here's an example of an asgi.py file for a Django application:

import os
from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_asgi_application()

In this example, we use get_asgi_application() to create an instance of the Django application and assign it to the application variable.

When to use WSGI vs ASGI

WSGI is a simpler interface and is widely supported by many web servers and hosting platforms. If you don't need the additional features provided by ASGI, such as support for WebSockets or long-lived connections, then WSGI may be the better choice.

ASGI is more advanced and provides support for asynchronous programming, which can improve the performance and scalability of your application. If you expect to have a high volume of simultaneous connections or long-lived connections, such as for real-time applications, then ASGI may be the better choice.

Deployment

Both WSGI and ASGI are used for deployment of Django applications to production environments. Typically, you will deploy your Django application to a web server, such as Apache or Nginx, and configure the web server to use either WSGI or ASGI to serve your application.

In summary, WSGI and ASGI are two interfaces for communicating between web servers and web applications written in Python. WSGI is a simpler and widely supported interface, while ASGI is more advanced and provides support for asynchronous programming. In Django, you can use wsgi.py and asgi.py files to provide entry points for WSGI and ASGI-compatible web servers, respectively.

Comparison table between WSGI and ASGI:

Feature WSGI ASGI
Synchronous or Asynchronous Synchronous only Both synchronous and asynchronous
Compatible web servers Apache with mod_wsgi, Nginx with uwsgi Daphne, Uvicorn, Hypercorn, Gunicorn with uvicorn
Suitable use cases Simple web applications with low to medium traffic High-traffic applications with long-lived connections, real-time functionality, and/or asynchronous tasks
Example Django application Django application that serves static content or minimal dynamic content Django Channels application that supports WebSocket connections for real-time chat or notifications

Synchronous

Synchronous programming is when tasks are executed one after another in a sequential order. Each task must be completed before the next one can start.

For example, if you were cooking a meal, you would chop all the vegetables first before moving on to preparing the protein, and then finish by cooking the entire meal.

This is similar to how you might complete a set of tasks on a to-do list, one after the other, without starting the next task until the previous one is finished.

Example use cases for synchronous programming in web applications include:

  • Simple web applications with low to medium traffic
  • Applications that do not require real-time functionality or long-lived connections
  • Applications that do not require complex or resource-intensive processing

When building a website, synchronous programming means that the server would need to wait until a task is complete before returning results to the user's browser. This can lead to slower response times and a less responsive user interface.

For example, if a user searches for a product, the server would need to complete the search before returning the results to the user.

Asynchronous

In contrast, asynchronous programming allows tasks to be executed simultaneously or in a non-sequential order. One task does not have to wait for the previous task to complete before starting.

For example, in cooking, you might start by chopping the vegetables and then while they are cooking, start preparing the protein, and then while that is cooking, start preparing the sauce.

Example use cases for asynchronous programming in web applications include:

  • High-traffic applications with long-lived connections, such as real-time chat or push notifications
  • Applications that require complex or resource-intensive processing, such as machine learning or data analysis
  • Applications that require efficient use of computing resources, such as cloud computing or serverless computing

With asynchronous programming, the server can initiate a task and continue processing other requests while the task is running in the background. This can lead to faster response times and a more responsive user interface.

For example, a real-time chat feature on a website can use asynchronous programming to allow messages to be sent and received in the background, creating a smoother and more real-time chat experience.

Overall, asynchronous programming is particularly useful for web applications that require real-time functionality, such as chat or notifications, or for applications with high traffic and long-lived connections. Examples of companies that use asynchronous programming include Instagram, which uses ASGI, and Amazon, which uses AWS Lambda.

Example of Chat Application

One example of a use case for asynchronous programming is a chat application. With synchronous programming, the server would need to wait for each message to be sent and received before displaying it to the user. With asynchronous programming, the messages can be sent and received in the background, allowing for a smoother and more real-time chat experience.

Popular chat applications that use asynchronous programming include:

  • WhatsApp
  • Slack
  • Facebook Messenger
  • Instagram

Instagram, in particular, uses Python and Django for their backend, and they have adopted asynchronous programming patterns using ASGI and the Django Channels library to handle long-lived connections for real-time functionality, such as real-time chat and push notifications.

Example of E-commerce Application

Another example of a use case for asynchronous programming is an e-commerce application. With synchronous programming, when a user places an order, the server would need to wait until the order is complete before returning a response to the user's browser. With asynchronous programming, the server can initiate the order and then continue processing other requests while the order is being processed in the background.

Popular e-commerce applications that use asynchronous programming include:

  • Amazon
  • Alibaba
  • eBay

In summary, synchronous programming executes tasks in a sequential order, while asynchronous programming allows for tasks to be executed simultaneously or in a non-sequential order. Asynchronous programming is particularly useful for web applications that require real-time functionality, such as chat or notifications, or for applications with high traffic and long-lived connections.

Introduction to web requests and responses

Section 1: What are web requests and responses?

Web requests and responses are the foundation of web development. They're the means by which a client, typically a web browser, communicates with a web server.

A web request is a message sent by the client to the server requesting some resource, such as a web page or an image. The server then responds to the request with a web response, which contains the requested resource.

Section 2: How do web requests and responses work?

Web requests and responses work by following the HTTP protocol. HTTP stands for Hypertext Transfer Protocol and it's the standard protocol for communication on the web.

When a client sends a request to a server, it sends an HTTP request message. The message contains a method, such as GET or POST, which specifies the type of request being made. It also includes a URL, which specifies the location of the resource being requested.

The server then processes the request and sends back an HTTP response message. The response message includes a status code, which indicates whether the request was successful or not, and the requested resource.

Section 3: The HTTP protocol

The HTTP protocol is a set of rules that defines how web requests and responses should be formatted and transmitted.

It specifies the format of the HTTP messages, which includes the request method, URL, headers, and body. It also specifies the format of the HTTP response, which includes the status code, headers, and body.

Section 4: Types of HTTP requests

There are several types of HTTP requests that can be made, but the two most common are GET and POST.

A GET request is used to retrieve a resource from the server. When a user types a URL into their browser, the browser sends a GET request to the server to retrieve the web page.

A POST request is used to send data to the server, such as when submitting a form.

Section 5: HTTP response status codes

HTTP response status codes are three-digit numbers that indicate the status of a web request. There are several status codes, but the most common ones are:

  • 200 OK: Successful response to a GET request
  • 201 Created: Successful response to a POST request that created a new resource
  • 204 No Content: Successful response to a request where no data is returned
  • 301 Moved Permanently: The requested resource has been permanently moved to a new URL
  • 302 Found: The requested resource has been temporarily moved to a new URL
  • 400 Bad Request: The server cannot process the request due to a client error
  • 401 Unauthorized: The client must authenticate to access the requested resource
  • 403 Forbidden: The server refuses to fulfill the request, even if authentication was provided
  • 404 Not Found: The requested resource could not be found on the server
  • 500 Internal Server Error: The server encountered an unexpected error while processing the request

Section 6: Django views and request processing

In Django, views are Python functions that handle HTTP requests and return HTTP responses. When a user makes a request to a Django application, the request is routed to a view function based on the URL requested.

The view function processes the request, typically by querying a database or performing some other operation, and returns an HTTP response.

Running the development server

Django comes with a lightweight web server to run your code quickly, without needing to spend time configuring a production server.

Start the development server by typing the following command in the shell prompt:

python manage.py runserver

You can run the Django development server on a custom host and port or tell Django to load a specific settings file, as follows:

python manage.py runserver 127.0.0.1:8001 --settings=mysite.settings

This server is only intended for development and is not suitable for production use. To deploy Django in a production environment, you should run it as a WSGI application using a web server, such as Apache, Gunicorn, or uWSGI, or as an ASGI application using a server such as Daphne or Uvicorn.

There are the different levels of verbosity available in Django's runserver command:

  • 0: Displays no output except for errors and system messages.
  • 1: Displays minimal output, such as the server's startup message and errors.
  • 2: Displays more detailed output, such as requests and responses.
  • 3: Displays even more detailed output, such as database queries and middleware information.
python manage.py runserver --verbosity 2

This will start the server with a verbosity level of 2, which displays more detailed output than the default verbosity level of 1.

Project settings

Let’s review some of the project settings:

  • DEBUG is a Boolean that turns the debug mode of the project on and off. If it is set to True, Django will display detailed error pages when an uncaught exception is thrown by your application. When you move to a production environment, remember that you have to set it to False. Never deploy a site into production with DEBUG turned on because you will expose sensitive project-related data.

  • ALLOWED_HOSTS is not applied while debug mode is on or when the tests are run. Once you move your site to production and set DEBUG to False, you will have to add your domain/host to this setting to allow it to serve your Django site.

  • INSTALLED_APPS is a setting you will have to edit for all projects. This setting tells Django which applications are active for this site. By default, Django includes the following applications:

    • django.contrib.admin - An administration site
    • django.contrib.auth - An authentication framework
    • django.contrib.contenttypes - A framework for handling content types
    • django.contrib.sessions - A session framework
    • django.contrib.messages - A messaging framework
    • django.contrib.staticfiles - A framework for managing static files
  • MIDDLEWARE is a list that contains middleware to be executed.

  • ROOT_URLCONF indicates the Python module where the root URL patterns of your application are defined.

  • DATABASES is a dictionary that contains the settings for all the databases to be used in the project. There must always be a default database. The default configuration uses an SQLite3 database.

  • LANGUAGE_CODE defines the default language code for this Django site.

  • USE_TZ tells Django to activate/deactivate timezone support. Django comes with support for timezone-aware datetimes. This setting is set to True when you create a new project using the startproject management command.

Projects and Applications

In Django, a project is considered a Django installation with some settings. An application is a group of models, views, templates, and URLs.

An application is a group of models, views, templates, and URLs. Applications interact with the framework to provide specific functionalities and may be reused in various projects.

You can think of a project as your website, which contains several applications, such as a blog, wiki, or forum, that can also be used by other Django projects.

Django Project
    APP 1
    APP 2
    APP 3
    .
    .
    APP N

Creating an application

Run the following command in the shell prompt from the project’s root directory:

python manage.py startapp blog

This will create the basic structure of the application, which will look like this:

blog/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

These files are as follows:

  • init.py - An empty file that tells Python to treat the blog directory as a Python package.
  • admin.py - This is where you register models to include them in the Django administration site—using this site is optional.
  • apps.py - This includes the main configuration of the blog application.
  • migrations - This directory will contain database migrations of the application. Migrations allow Django to track your model changes and synchronize the database accordingly. This directory contains an empty __init__.py file.
  • models.py - This includes the data models of your application; all Django applications need to have a models.py file but it can be left empty.
  • tests.py - This is where you can add tests for your application.
  • views.py - The logic of your application goes here; each view receives an HTTP request, processes it, and returns a response.

With the application structure ready, we can start building the data models for the blog.

Migrations

  • Run the following command in the shell prompt from the root directory of your project:
python manage.py makemigrations
  • Run the following command from the shell prompt to inspect the SQL output of your first migration:
python manage.py sqlmigrate blog 0001

Setting up URLs and Views in Django

Using path in URLs

  • In views.py of your app, create a function that handles the request/response of the page.
from django.shortcuts import render
from django.http import HttpResponse

def hello_world(request):
    return HttpResponse('Hello, Baby!!!')
  • In urls.py of your project, import the views module from your app and In the urlpatterns list, add a path to the view function.
from django.contrib import admin
from django.urls import path

from firstapp import views

urlpatterns = [
    path("admin/", admin.site.urls),
    path('', views.hello_world, name="hello")
]

Different ways for urls

  • First, let's start with the urls.py file of the project. This file defines the URLs for the project and specifies which views will handle the HTTP requests for each URL.
from django.contrib import admin
from django.urls import path, include

from firstapp import views
from firstapp import urls

urlpatterns = [
    path("admin/", admin.site.urls),
    path('', views.hello_world, name="hello 1"),
    path('firstapp/', include('firstapp.urls'))
]
  • Next, let's look at the urls.py file of the firstapp app. This file defines the URLs for the app and specifies which views will handle the HTTP requests for each URL.
  • views.py
from django.shortcuts import render
from django.http import HttpResponse

def hello_world(request):
    return HttpResponse('Hello, Baby!!!')

def hello_name(request, name):
    return HttpResponse('Hello, {}!!!'.format(name))

def month_archive(request, year, month):
    return HttpResponse('Month archive: {}/{}'.format(month, year))

def index(request):
    return HttpResponse('Hello, world!')
  • urls.py
from django.urls import path, re_path
from firstapp import views

urlpatterns = [
    # Example 1: Basic path
    path('hello/', views.hello_world),

    # Example 2: Path with parameter
    path('hello/<name>/', views.hello_name),

    # Example 3: Path with multiple parameters (Interger)
    path('articles/<int:year>/<int:month>/', views.month_archive),
    
    # Example 4: Parameter (String)
    path("user/<str:name>/", views.user_name, name="user"),

    # Example 5: Root path
    path('', views.index, name='index'),

    # Example 6: Path with regular expression
    re_path(r'^hello/(?P<name>\w+)/$', views.hello_name),
]

r'^hello/(?P<name>\w+)/$' matches URLs like "hello/world/" or "hello/123_abc/", capturing the name argument and passing it to the hello_name view function.

r'^hello/$' only matches the URL "hello/" and maps to the hello_world view function without capturing any arguments.

some other important

path('blog/<int:id>/', views.blog_detail),
path('user/<str:name>/', views.user_profile),
path('article/<uuid:uuid>/', views.article_detail),

PATH AND RE_PATH

Path is a simple way to define URL patterns for views. It is used when you want to match a specific URL pattern with a specific view function.

path('articles/', views.article_list),
path('articles/<int:pk>/', views.article_detail),

In the above example, the first URL pattern matches the URL /articles/ and maps to the article_list view function.

The second URL pattern matches URLs of the form /articles/{id}/, where {id} is an integer, and maps to the article_detail view function.

  • re_path is used when you need to use regular expressions to define URL patterns for views. It is more powerful than path, but also more complex. For example:
re_path(r'^articles/$', views.article_list),
re_path(r'^articles/(?P<pk>[0-9]+)/$', views.article_detail),

In the above example, the first URL pattern matches the URL /articles/ and maps to the article_list view function.

The second URL pattern uses a regular expression to match URLs of the form /articles/{id}/, where {id} is an integer. The regular expression (?P<pk>[0-9]+) captures the integer value as a named group pk, which is then passed to the article_detail view function.

In general, you should use path when you can, and only use re_path when you need to use regular expressions to define more complex URL patterns.

UUID

UUID (Universally Unique Identifier) is a 128-bit unique identifier or a string of 32 hexadecimal (base-16) characters, where each character represents 4 bits of the UUID that is used to identify objects in a distributed computing environment.

UUIDs have 2^128 (or approximately 3.4 x 10^38) possible combinations, which ensures a very low probability of collision even when generating a large number of UUIDs. The large number of possible combinations is one of the reasons why UUIDs are popular for unique identification.

In the context of URLs, UUIDs can be used as a unique identifier for resources, such as articles or posts, to generate unique and unpredictable URLs.

Using UUIDs in URLs can be beneficial in a few ways:

  • They provide a globally unique identifier for resources that don't have a predictable or sequential ID.

  • They can improve security by making it harder for attackers to guess or manipulate URLs.

  • They can prevent conflicts when merging data from different sources, since UUIDs are guaranteed to be unique.

Here's a basic example of how to generate a UUID in Python:

import uuid

new_uuid = uuid.uuid1()
print(f"UUID1 = {new_uuid}")

print(f'UUID3 = {uuid.uuid3(new_uuid, "name")}')

print(f"UUID4 = {uuid.uuid4()}")

new_uuid5 = uuid.uuid5(new_uuid, "same")
print(f"UUID5 = {new_uuid5}")

Now, let's move on to how we can use UUIDs in Django.

from django.http import HttpResponse
import uuid

def post_uuid(request, uuid):
    # Do something with the UUID
    return HttpResponse(f"Received UUID: {uuid}")

Note: We will do the following later, For now just see it

Now, let's say you want to use the UUID to retrieve a post object from your database. Here's an example:

  • views.py
from django.shortcuts import get_object_or_404
from myapp.models import Post

def post_uuid(request, uuid):
    post = get_object_or_404(Post, uuid=uuid)
    return HttpResponse(f"Title: {post.title}, Content: {post.content}")
  • models.py
from django.db import models
import uuid

class Post(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    title = models.CharField(max_length=255)
    content = models.TextField()

    def __str__(self):
        return self.title

Using UUIDs in URL patterns can be useful for generating unique and unpredictable URLs for resources in your Django application, especially in cases where you don't want to expose sequential or predictable IDs.

  • It can also be used as primary keys for database models in Django as we used in earlier example of models.py
  • It can be used for session IDs to ensure that each user's session is unique and cannot be easily guessed or hijacked by attackers.

SLUGS

A slug is a human-readable part of a URL that identifies a resource, typically representing the name or title of the resource in a URL-friendly format.

Slugs usually consist of a string of characters (such as letters, numbers, hyphens, or underscores) that are separated by hyphens

Slugs are used in web applications to make URLs more user-friendly and search engine optimized by providing descriptive information in the URL.

  • Slugs can be used to make URLs more readable and memorable for users.
  • Slugs can also be beneficial for search engine optimization (SEO).

** I prefer Slug over UUID in blog posts. It can be generated from post attributes, like the title or name. They are meaningful to the user and easy to optimize for SEO with descriptive keywords. **

We'll discuss UUID and Slug when we read MODELS in clear.

For now, we can use slugs in urls.py and HttpResponse in views.py without needing to define a model.

  • In urls.py:
from django.urls import path
from . import views

urlpatterns = [
    path('blog/<slug:post_slug>/', views.post_detail, name='post_detail'),
]
  • In views.py:
from django.http import HttpResponse

def post_detail(request, post_slug):
    return HttpResponse(f'This is the detail page for post "{post_slug}"')

When a user visits a URL matching /blog/slug:post_slug/, Django calls the post_detail view function with post_slug set to the slug in the URL. The function returns an HttpResponse object with the appropriate content and headers.

For example, /blog/my-first-post/ calls post_detail with post_slug='my-first-post' and returns an HttpResponse with "This is the detail page for post 'my-first-post'".

Views

The most commonly used methods for generating HTTP responses in Django views are HttpResponse and render.

  • HttpResponse is used to return simple text or HTML responses. You can pass a string as an argument to HttpResponse, and it will be rendered as text in the user's browser.

  • render is used to render Django templates with context data and return the resulting HTML. It takes a request object, a template name, and a dictionary of context data as arguments.

That being said, the other response methods mentioned below are also used frequently depending on the specific use case.

  • JsonResponse: This method returns a JSON-encoded response.
  • FileResponse: This method returns a file as the response.
  • StreamingHttpResponse: This method returns a streaming response.
  • HttpResponseRedirect: This method redirects the user to another URL.
  • HttpResponsePermanentRedirect: This method returns a permanent redirect to another URL.
  • HttpResponseBadRequest: This method returns a 400 Bad Request response.
  • HttpResponseNotFound: This method returns a 404 Not Found response.
  • HttpResponseServerError: This method returns a 500 Internal Server Error response.

Types

In Django, there are mainly three types of views:

  • Function-Based Views (FBVs)
  • Class-Based Views (CBVs)
  • Generic Class-Based Views (GCBVs)

FBVs

Function-Based Views (FBVs) are the simplest type of view in Django. They are defined as Python functions that take a request object as input and return an HTTP response. Here's an example of a simple FBV:

from django.http import HttpResponse

def hello_world(request):
    return HttpResponse("Hello, World!")

In this example, the hello_world function takes a request object as input and returns an HttpResponse object with the text "Hello, World!". When a user visits the URL associated with this view, the text "Hello, World!" will be displayed in their browser.

CBVs

Class-Based Views (CBVs) are a more advanced type of view in Django. They are defined as Python classes that inherit from Django's View class and override its get() or post() method to handle requests. Here's an example of a simple CBV:

from django.views import View
from django.http import HttpResponse

class HelloWorldView(View):
    def get(self, request):
        return HttpResponse("Hello, World!")

In this example, the HelloWorldView class inherits from Django's View class and overrides its get() method to return an HttpResponse object with the text "Hello, World!".

While using class based view you should alwasys inherit from View class to get access to basic view functionality. Define methods that handle HTTP requests with the appropriate method name (e.g., get(), post(), etc.).

  • get(): handles GET requests
  • post(): handles POST requests
  • put(): handles PUT requests
  • delete(): handles DELETE requests
  • head(): handles HEAD requests
  • options(): handles OPTIONS requests
  • trace(): handles TRACE requests
  • patch(): handles PATCH requests

Example:

  • views.py
class MyView(View):
    def get(self, request):
        return HttpResponse('Hello, World!')
  • urls.py
path('myview/', views.MyView.as_view(), name='myview'),

It is not compulsary to inherit from View class but you will have to manually handle things like URL routing, request/response handling, and other functionalities provided by Django's views

GCBVs

Generic Class-Based Views (GCBVs) are a more powerful type of CBV in Django that provide pre-built functionality for common use cases, such as displaying lists or detail views of database objects. They are defined as Python classes that inherit from Django's generic views, such as ListView or DetailView. Here's an example of a simple GCBV:

from django.views.generic import TemplateView

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

In this example, the HomePageView class inherits from Django's TemplateView and sets its template_name attribute to the name of the template to render. When a user visits the URL associated with this view, the home.html template will be rendered and displayed in their browser.

Here's a table with the classes and methods of the commonly used Django generic views, along with a brief example for each:

Class Description Methods Example
ListView Displays a list of objects from a model queryset(), get_queryset(), context_object_name(), paginate_queryset(), get_paginate_by(), get_context_data() A blog website uses ListView to display a list of all blog posts
DetailView Displays a single object from a model queryset(), get_queryset(), context_object_name(), get_object() A blog website uses DetailView to display a single blog post
CreateView Creates a new object for a model form_valid(), form_invalid(), get_form(), get_success_url() A blog website uses CreateView to allow users to create new blog posts
UpdateView Updates an existing object for a model form_valid(), form_invalid(), get_object(), get_form(), get_success_url() A blog website uses UpdateView to allow users to edit and update existing blog posts
DeleteView Deletes an existing object for a model delete(), get_object(), get_success_url() A blog website uses DeleteView to allow users to delete existing blog posts
TemplateView Renders a template without a model template_name(), get_context_data() A blog website uses TemplateView to render static pages like the home page, about page, and contact page

Here's an example usage of ListView:

# views.py

from django.views.generic import ListView
from .models import BlogPost

class BlogPostListView(ListView):
    model = BlogPost
    template_name = 'blogpost_list.html'
    context_object_name = 'blogposts'
    paginate_by = 10

    def get_queryset(self):
        # return queryset of all blog posts
        return BlogPost.objects.all()

In the above example, we've created a BlogPostListView that inherits from ListView. We've set the model to BlogPost, which tells the view to use the BlogPost model to display a list of blog posts. We've also set the template_name to 'blogpost_list.html', which is the name of the template that will be used to render the list of blog posts. The context_object_name is set to 'blogposts', which is the name of the variable that will be used in the template to represent the list of blog posts. Finally, we've set the paginate_by to 10, which tells the view to paginate the list of blog posts with 10 posts per page.

We've also overridden the get_queryset() method to return a queryset of all blog posts. This queryset will be used by the view to display a list of all blog posts.

Templates in Django

Templates are text files that define the structure and appearance of the web pages served by the application.

Templates can be written in HTML or other template languages like Jinja2. The primary function of templates is to separate the presentation logic from the application logic, allowing developers to focus on building the application's functionality.

Always make Templates in Apps not in Project directory

The "templates" folder should be created within your app's directory, not in the project directory. When Django searches for templates to render, it looks for them in the "templates" subdirectory of each app listed in the INSTALLED_APPS setting.

For example, let's say you have an app called "myapp" in your Django project. The directory structure would be something like this:

myproject/
    myproject/
        settings.py
        urls.py
        ...
    myapp/
        templates/
            myapp/
                my_template.html
        views.py
        models.py
        ...
    ...

In a Django project, the recommended way to organize templates is to have a separate templates directory for each app. So in your case, you should create a "templates" directory within each app, like this:

portfolio/
    blog/
        templates/
            blog/
                base.html
                post_detail.html
                ...
        ...
    skills/
        templates/
            skills/
                base.html
                skill_detail.html
                ...
        ...
    services/
        templates/
            services/
                base.html
                service_detail.html
                ...
        ...
    ...

If you like you can create a seperate app called core or main for handling main/home page in the following way:

portfolio/
    core/
        templates/
            core/
                base.html
                index.html
                ...
        views.py
        urls.py
        ...
    blog/
        templates/
            blog/
                base.html
                post_detail.html
                ...
        views.py
        urls.py
        ...
    skills/
        templates/
            skills/
                base.html
                skill_detail.html
                ...
        views.py
        urls.py
        ...
    services/
        templates/
            services/
                base.html
                service_detail.html
                ...
        views.py
        urls.py
        ...
    ...

Note: If you don't want to make a seperate app , you can simply make a templates folder in your Base Directory.

Steps

Once you are inside the base directory, create a new directory called templates using the mkdir command:

mkdir templates

Now you can add the following in the TEMPLATES varibale of setting.py:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'APP_DIRS': True,
        'DIRS': [
            os.path.join(BASE_DIR, 'templates')
        ],
        ...
    },
]

This tells Django to look for templates in the templates subdirectory of each installed app (because APP_DIRS is set to True), as well as in the BASE_DIR/templates directory.

NOTE: The os.path.join() function joins two or more path components into a single path. In the example I provided earlier:

os.path.join(BASE_DIR, 'templates'),

BASE_DIR is a variable that contains the base directory of your Django project, and 'templates' is the name of the directory you want to add to it.

The os.path.join() function takes care of adding the appropriate directory separator (i.e. / or \, depending on your operating system) between the components.

Template Tags

Here's a table summarizing the syntax of Django templates:

Syntax Description
{{ variable }} Renders the value of a variable
{% tag %} Executes a template tag
{% tag argument %} Executes a template tag with an argument
{% tag argument1 argument2 %} Executes a template tag with multiple arguments
{% tag %}...{% endtag %} Executes a template tag with a block of content
{# comment #} Adds a comment to a template
{{ variable l filter }} simple functions that modify data before Django renders it.
{% if condition %}...{% endif %} Renders a block of content if a condition is true
{% if condition %}...{% else %}...{% endif %} Renders one block of content if a condition is true, and another block if it's false
{% for item in list %}...{% endfor %} Loops over a list and renders a block of content for each item
{% url 'name' arg1 arg2 %} Generates a URL for a named URL pattern with optional arguments
{% extends 'base.html' %} Extends a base template
{% block content %}...{% endblock %} Defines a block of content to be overridden in an extending template
{{ form.as_p }}} Renders a Django form as a series of <p> tags

Examples:

  • Comment tag:{% comment %} This is a comment {% endcomment %}
  • If tag:{% if user.is_authenticated %} Welcome back, {{ user.username }}! {% else %} Please log in. {% endif %}
  • For loop tag:{% for item in item_list %} {{ item }} {% endfor %}
  • URL tag:{% url 'app_name:view_name' arg1 arg2 %}
  • Output tag:{{ variable }}
  • Inheritance tag:{% extends 'base.html' %}
  • Block tag:{% block content %} Content goes here {% endblock %}
  • Include tag:{% include 'navbar.html' %}

Examples:

  1. Render a variable: Use double curly braces ({{ }}) to render the value of a variable:
<h1>Hello, {{ name }}!</h1>

If name is set to "John", the rendered HTML will be:

<h1>Hello, John!</h1>
  1. Execute a template tag: Use curly braces with a percent sign ({% %}) to execute a template tag:
{% if condition %}
    <p>Condition is true.</p>
{% endif %}
  1. Use template tags with arguments: You can also pass arguments to template tags:
{% url 'blog_post' post.id %}

This will generate a URL to a named URL pattern called blog_post and pass the id of a post as an argument.

  1. Apply filters to variables: Filters can modify the value of a variable before it's rendered:
<p>{{ text|truncatewords:10 }}</p>

This will render text with a filter that limits the number of words to 10.

  1. Use if-else blocks: You can use if-else blocks to render different content based on a condition:
{% if user.is_authenticated %}
    <p>Welcome back, {{ user.username }}!</p>
{% else %}
    <p>Please log in.</p>
{% endif %}
  1. Use for loops: You can use for loops to iterate over a list and render content for each item:
<ul>
{% for item in items %}
    <li>{{ item }}</li>
{% endfor %}
</ul>

This will render an unordered list with one list item for each item in items.

  1. Use extends and blocks for template inheritance: You can use the extends tag to inherit from a base template and override specific blocks of content:
{% extends "base.html" %}

{% block content %}
    <h1>About Us</h1>
    <p>We are a company that makes things.</p>
{% endblock %}

This will extend a base template called base.html and override the content block with new content.

  1. Use Django forms in templates: You can use Django forms in templates to render HTML form elements:
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Save</button>
</form>

This will render a form with a CSRF token and all form fields rendered as paragraphs (

tags).

Static Files

It's recommended to create a single "static" folder at the root level of your Django project to manage all static files, such as CSS, JS, and images. This allows for better organization and easier management of static files. The folder structure would look like this:

    myproject/
    static/
        css/
        js/
        img/

Based on your requirements, you can add some tweaks, for example if you have multiple apps and want to handle all the apps static files differently then you can follow the following folder structure.

    myproject/
    static/
        css/
        js/
        img/
        app 1/
            css/
            js/
            img/
        app 2/
            css/
            js/
            img/
        and so on .....

To start serving static files in Django, you should create a folder named static in your project's root directory. This folder will contain all of your static files, such as images, CSS files, and JavaScript files.

Once you've created the static folder, you need to add the following settings in your settings.py file:

STATIC_URL = "static/"
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static/")
]

The STATIC_URL setting specifies the URL that will be used to access static files. In this case, we're using the URL static/.

The STATICFILES_DIRS setting specifies a list of directories where Django should look for static files. In this case, we're telling Django to look for static files in the static folder that we just created.

To test that your static files are being served correctly, you can add an image to the static/images folder, for example static/images/simple.jpg. Then, if you go to the following URL in your browser:

127.0.0.1:8000/static/images/simple.jpg

You should see the image displayed in your browser. This confirms that your static files are being served correctly.

To add the image simple.jpg from the static folder to your index.html file, you would use the following HTML code:

<img src="{% static 'images/simple.jpg' %}" alt="A simple image">

This code uses the {% static %} template tag to generate the correct URL for the image, which includes the STATIC_URL prefix that we set in settings.py.

In addition to adding the HTML code to display the image, you also need to load the static template tag library in your template. To do this, add the following code to the beginning of your index.html file:

{% load static %}

This code loads the static template tag library, which allows you to use the {% static %} template tag to reference your static files. It should be placed below the <!DOCTYPE html> declaration and before any other code in your HTML file.

Note that you can use the same approach to serve other types of static files, such as CSS and JavaScript files. Simply add them to your static folder, reference them using the {% static %} template tag, and they will be served by Django.

For example, to add a CSS file named styles.css, you would create a file at static/css/styles.css, and then reference it in your HTML file like this:

<link rel="stylesheet" href="{% static 'css/styles.css' %}">

Similarly, to add a JavaScript file named script.js, you would create a file at static/js/script.js, and then reference it in your HTML file like this:

<script src="{% static 'js/script.js' %}"></script>

By using the {% static %} template tag to reference your static files, you can ensure that they are served correctly regardless of the location of your project or the settings of your web server.

Template Inheritance

Let's say we have multiple html document that contains the common elements such as header and footer basically. Instead of using it again and again we can use Template Inheritance.

Template Inheritance is a feature in Django's templating system that allows you to create a base HTML template with common elements, and then inherit from it in child templates that add their own content.

To begin you should first create a base.html file that contains the common elements you want to reuse across multiple pages of your website, such as the navbar and footer. For example:

<!-- base.html -->

<head>
    <title>{% block title %}My Website{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
    <!-- Navbar -->
    <nav>
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
    </nav>

    <!-- Main Content -->
    <div class="container">
        {% block content %}
        {% endblock %}
    </div>

    <!-- Footer -->
    <footer>
        <p>&copy; 2023 My Website</p>
    </footer>
</body>

In this template, we've created a basic HTML skeleton with a navbar, container for main content, and a footer. We've also added a {% block %} tag for the title, content, and other elements that will be overridden in child templates.

Create a child HTML template for the home page of your website, for example practice.html. This template will inherit the layout and styling of base.html and will override the content block with its own HTML. For example:

<!-- practice.html -->

{% extends 'base.html' %}

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

{% block content %}
	<div class="main-content">
		<h1>Welcome to My Website!</h1>
		<p>This is the home page of my website.</p>
		<p>Feel free to look around and check out my blog!</p>
	</div>
{% endblock %}

In this template, we're using the {% extends %} tag to inherit the layout and styling of base.html, and we're overriding the content block with our own HTML for the home page. We've added a simple welcome message and some text to demonstrate the use of this template.

And we can do same for blog.html too:

<!-- blog.html -->

{% extends 'base.html' %}

{% block title %}Blog Page{% endblock %}

{% block content %}
	<div class="main-content">
		<h1>My Blog</h1>
		<p>Welcome to my blog! Here are some recent posts:</p>

		<!-- Blog Posts -->
		<div class="blog-post">
			<h2>Post Title 1</h2>
			<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vel eros vel nibh malesuada aliquet sed eget felis.</p>
		</div>

		<div class="blog-post">
			<h2>Post Title 2</h2>
			<p>Nullam in risus quis lectus feugiat vestibulum. Praesent id tellus magna.</p>
		</div>

		<!-- Pagination -->
		<div class="pagination">
			<a href="#">Previous</a>
			<a href="#">1</a>
			<a href="#">2</a>
			<a href="#">3</a>
        	</div>
{% endblock %}

In this template, we're using the {% extends %} tag to inherit the layout and styling of base.html, and we're overriding the content block with our own HTML for the blog page. We've added a couple of sample blog posts and a pagination section to demonstrate the use of this template.

Navigating From One Page to Another

In the urls.py file, define a URL pattern for each page you want to link to.

path("", views.index, name="homePage"), 
path("blog/", views.blog, name="blogPage"),
path("forms/", views.form, name="formPage")

Now i will show you the actual use of name. In the base.html, update the links in your navbar to point to the appropriate URLs using the {% url %} template tag. For example:

<div class="navbar">
	<a href="{% url 'homePage' %}">Home</a>
	<a href="{% url 'blogPage' %}">Blog</a>
	<a href="{% url 'formPage' %}">Forms</a>
</div>

In this example, we are using the {% url %} tag to generate URLs for the home, blog, and form views. The tag takes a view name as an argument (in quotes) and generates the appropriate URL based on the URL patterns defined in urls.py.

In case of multiple apps, you can do like this:

<a href="{% url 'firstapp:homePage' %}">Home</a>
<a href="{% url 'secondapp:aboutPage' %}">About</a>

Introduction to Django models

What are models?

  • A model is a Python class that represents a database table.
  • Each attribute of the class represents a field/columns in the table, and each instance of the class represents a row in the table.
  • By defining models, you can interact with the database using high-level abstractions that simplify querying, data manipulation, and data validation.

Why use models in Django?

  • Django models provide a way to define the structure of your database tables in Python code, making it easier to maintain and modify your database schema over time.
  • Models provide a powerful Object-Relational Mapping (ORM) layer that abstracts away the details of the database, allowing you to interact with the data using Python objects and methods.
  • Models enable you to define data validation rules and data manipulation logic in one place, which helps to ensure the integrity of your data and the consistency of your code.
  • Models also provide a convenient way to generate HTML forms for creating and editing records in the database, using the built-in ModelForm class.

Creating a model

To create a model in Django, you define a Python class that inherits from the django.db.models.Model class. Each attribute of the class represents a field/column in the database table, and each instance of the class represents a row in the table.

from django.db import models

class MyModel(models.Model):
    field1 = models.CharField(max_length=100)
    field2 = models.IntegerField()
    field3 = models.DateTimeField()

In this example, MyModel is the name of the model or entity, and field1, field2, and field3 are the names of the fields or columns in the model. These fields define the structure and content of the model and determine how it's stored in the database.

Rows are the individual records or instances of a model that are stored in a database table.

Registering Models

To use your models in your Django project, you need to register them with the Django admin page. To do this, you need to create an admin.py file in the same app where your models are defined. In this file, you can import your models and then register them with the admin page. For example:

from django.contrib import admin
from .models import MyModel

admin.site.register(MyModel)

In this example, we are importing MyModel from the models.py and then registering it with the admin page using the admin.site.register() method.

The Django Admin Page

The Django admin page provides a user-friendly interface for managing your database records. When you register your models with the admin page, you can view and edit your records using this interface.

By default, the admin page includes functionality for creating, reading, updating, and deleting records. You can also customize the admin page to include additional functionality, such as filtering, searching, and sorting your records.

To access the Django admin page, you need to create a superuser account. To do this, run the following command in your terminal:

python manage.py createsuperuser

Once you have created a superuser account, you can log in to the admin page by navigating to http://localhost:8000/admin in your web browser and entering your superuser credentials.

From the admin page, you can view and edit your records, as well as perform various other tasks such as creating new records, deleting records, and exporting data to CSV or Excel files.

You can also customize the admin page by creating custom views, filters, and forms.

After logging into the admin page, you will see that several sections are already available. These sections are part of Django's built-in functionality, which includes managing user authentication and permissions through the django.contrib.auth app. However, the admin page itself is provided by the django.contrib.admin app.

Some Common Fields

Basic model data types and fields list

  • AutoField: IntegerField that increments automatically.
  • BigAutoField: 64-bit integer that guarantees to fit numbers from 1 to 9223372036854775807.
  • BigIntegerField: 64-bit integer that guarantees to fit numbers from -9223372036854775808 to 9223372036854775807.
  • BinaryField: stores raw binary data.
  • BooleanField: true/false field, default form widget is CheckboxInput.
  • CharField: stores text-based values.
  • DateField: stores a date, represented by a datetime.date instance in Python.
  • DateTimeField: stores date and time, represented by a datetime.datetime instance in Python.
  • DecimalField: stores a fixed-precision decimal number, represented by a Decimal instance in Python.
  • DurationField: stores periods of time.
  • EmailField: CharField that checks the value is a valid email address.
  • FileField: file-upload field.
  • FloatField: floating-point number represented by a float instance in Python.
  • ImageField: inherits from FileField and validates the uploaded object is a valid image.
  • IntegerField: integer field that supports values from -2147483648 to 2147483647 in all supported databases.
  • GenericIPAddressField: stores an IPv4 or IPv6 address in string format.
  • NullBooleanField: like a BooleanField, but allows NULL as one of the options.
  • PositiveIntegerField: like an IntegerField, but must be either positive or zero.
  • PositiveSmallIntegerField: like a PositiveIntegerField, but only allows values under a certain point.
  • SlugField: stores a short label containing only letters, numbers, underscores or hyphens, generally used in URLs.
  • SmallIntegerField: like an IntegerField, but only allows values under a certain point.
  • TextField: large text field, default form widget is a Textarea.
  • TimeField: stores a time, represented by a datetime.time instance in Python.
  • URLField: stores a URL, validated by URLValidator.
  • UUIDField: stores universally unique identifiers, using Python’s UUID class.

Relationship Fields

Django also defines a set of fields that represent relations.

  • ForeignKey: many-to-one relationship, requires the class to which the model is related and the on_delete option.
  • ManyToManyField: many-to-many relationship, requires the class to which the model is related.
  • OneToOneField: one-to-one relationship, similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object.

Simple Book Model

Now that we know a brief about Model, we'll practice it by making a Simple Book App.

Here's an example model for a blog post:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=200)
    publication_date = models.DateField()
    description = models.TextField()
    cover_image = models.ImageField(upload_to='book_covers/')

In this example, we define five fields for the Book model:

  • title: a CharField with a maximum length of 200 characters, which will store the title of the book.
  • author: a CharField with a maximum length of 200 characters, which will store the name of the book's author.
  • publication_date: a DateField which will store the publication date of the book.
  • description: a TextField which will store a description of the book.
  • cover_image: an ImageField which will store the cover image of the book. The upload_to parameter specifies the directory where uploaded images should be stored.

Make sure you register you model in admin.py:

admin.site.register(Book)

Now that we have defined our Book model, we need to create the corresponding database table. To do this, run the following command in your terminal:

python manage.py makemigrations books

This command will create a new migration file in the books/migrations directory, which defines the changes we made to the database schema. Next, apply the migration by running:

python manage.py migrate

This will create the database table for the Book model.

Now that we have created the Book model and the corresponding database table, we can use it in our views and templates to display and manipulate book data.

For example, in your views.py file, you could define a function to retrieve all the books from the database and pass them to your index.html template:

from django.shortcuts import render
from .models import Book

def book_list(request):
    books = Book.objects.all()
    return render(request, 'index.html', {'books': books})

Here, we've imported the Book model from our models.py file, and defined a new view called book_list that retrieves all the Book objects from the database and passes them to the book_list.html template.

Now let's modify our book_list.html template to display the list of books:

{% extends 'firstapp/base.html' %}

{% block title %}My Book Store{% endblock %}

{% block content %}
<section id="featured">
    <h2>Featured Books</h2>
    <ul>
        {% for book in books %}
        <li>
            <article>
                {% if book.cover_image %}
                <img src="{{ book.cover_image.url }}" alt="{{ book.title }} cover">
                {% endif %}
                <h3>{{ book.title }}</h3>
                <p>{{ book.description }}</p>
                <p>by {{ book.author }}</p>
                <p>Published: {{ book.published_date }}</p>
                <a href="#">Learn More</a>
            </article>
        </li>
        {% endfor %}
    </ul>
</section>
{% endblock %}

Here, we've added a loop that iterates over the books list that we passed to the context dictionary in the view function. Inside the loop, we access each book's attributes using the dot notation, such as book.title, book.author, and book.published_date.

Builtin Apps and Models

You can use the Django shell to see a list of all installed apps and their models.

python manage.py shell

Then enter the following commands:

from django.apps import apps
for app in apps.get_app_configs():
    print(app.verbose_name)
    for model in app.get_models():
        print(f"  {model.__name__}")

This will print out a list of all installed apps and their associated models.

Generally It will show like the following:

App name Model name Description
admin LogEntry Provides a web-based interface for managing data in your Django application.
Stores log entries for actions taken in the admin interface.
auth Permission
Group
User
Provides built-in user authentication and authorization functionality.
Permission stores individual permissions,
Group represents a collection of users with the same permissions,
User represents a user account.
contenttypes ContentType Allows models to be generic across different types of content.
For example, a Blog model might be associated with a ContentType object to store different types of blog posts.
sessions Session Provides a way to store session data for each user.
A new Session object is created when a user logs in to your application, and stores information about their session.
messages Message Provides a way to store messages that can be displayed to users.
For example, you might use this framework to show a message to a user after they successfully submit a form.
staticfiles N/A Provides a way to manage static files (such as CSS, JavaScript, and images) for your Django application.

I hope this helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment