KEMBAR78
Django Teaching Notes Documentation 2.o | PDF | Model–View–Controller | Computer Programming
0% found this document useful (0 votes)
36 views136 pages

Django Teaching Notes Documentation 2.o

Django is a powerful, open-source Python framework for building web applications, emphasizing rapid development, security, and scalability. It is widely used in various industries for applications such as content management systems, e-commerce, and educational platforms. The document also covers installation procedures, project creation, and the MVT architecture, highlighting the differences between MVC and MVT patterns.

Uploaded by

Vinni Boss
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views136 pages

Django Teaching Notes Documentation 2.o

Django is a powerful, open-source Python framework for building web applications, emphasizing rapid development, security, and scalability. It is widely used in various industries for applications such as content management systems, e-commerce, and educational platforms. The document also covers installation procedures, project creation, and the MVT architecture, highlighting the differences between MVC and MVT patterns.

Uploaded by

Vinni Boss
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 136

DJANGO TEACHING NOTES DOCUMENTATION 2.

0:

SECTION:I
**************

1. Django Overview

Introduction

Django is a powerful Python framework designed to streamline the process of building web
applications. It handles many of the complex tasks involved in web development, allowing
developers to focus on writing their apps rather than reinventing the wheel. Emphasizing the
principle of DRY (Don’t Repeat Yourself), Django promotes the reusability of components and
includes ready-to-use features like authentication systems, database connections, and CRUD
(Create, Read, Update, Delete) operations.

Django is recognized for its:

● High-level design: Encourages rapid development and clean, pragmatic design.


● Speed: Enables developers to take applications from concept to completion quickly.
● Security: Django takes security seriously, helping developers avoid common security
pitfalls.
● Scalability: It powers some of the busiest sites on the web, demonstrating its ability to
scale quickly and flexibly.

Django is both free and open source, built and maintained by a community of experienced
developers.

Django in the Real World

Django is widely adopted across various industries and use cases:

● Content Management Systems (CMS): Platforms like Django CMS and Wagtail offer
robust content management solutions, making it easier to manage web content.
● Social Networking Sites: Django powers parts of popular social networking platforms
like Instagram, managing user interactions, and content seamlessly.
● E-commerce Platforms: Sites like Pinterest and The Washington Times utilize
Django for its scalability and flexibility, handling the complexities of online retail
effectively.
● Educational Platforms: Django is the backbone of educational platforms like Udemy
and Khan Academy, managing course content, user accounts, and interactions.
● News Websites: News outlets such as The Guardian and Mozilla Foundation’s
Common Voice project rely on Django for content management and user engagement.
● Healthcare Applications: Django is used in healthcare apps for managing patient
records, scheduling appointments, and facilitating communication between healthcare
providers and patients.
● Government Websites: Various government agencies use Django to build websites and
applications that provide essential services and information to citizens.
● Data Analytics Platforms: Django is employed by data analytics platforms like Civis
Analytics for managing data, user authentication, and generating dynamic reports.
● Financial Services: Django powers web applications in the financial sector, supporting
online banking, financial planning, and investment management.
● Software as a Service (SaaS) Platforms: Many SaaS companies leverage Django for
its scalability, security, and ease of development to build core applications.

2. Django Installation

What is a Virtual Environment?

A virtual environment (often abbreviated as virtualenv) is an essential tool in Python


development that allows you to create isolated environments for your projects. Each virtual
environment can have its own Python interpreter and set of dependencies, separate from the
global Python environment and other virtual environments.

Why Use Virtual Environments?

1. Isolation:
Virtual environments allow you to isolate the dependencies of one project from those of
another. This prevents conflicts between different projects that might require different
versions of the same package.
2. Dependency Management:
With virtual environments, you can install project-specific dependencies without affecting
the global Python installation. This ensures that your project uses the correct versions of
packages.
3. Reproducibility:
Virtual environments help ensure that your project is reproducible across different
environments. By specifying dependencies within the virtual environment, you can easily
recreate the environment on another machine, making it easier to collaborate with others
and deploy your project in production.
4. Cleanliness:
Virtual environments keep your global Python environment clean by isolating
project-specific dependencies. This helps avoid clutter and makes it easier to maintain a
tidy development environment.
Installation of a Virtual Environment

Creating a virtual environment (virtualenv) in Python allows you to create isolated


environments for your projects, each with its own dependencies. Here’s how you can create a
virtual environment:

Step 1: Install virtualenv

If you haven't already installed virtualenv, you can do so using pip, Python's package
manager. Open your terminal or command prompt and run the following command:

“pip install virtualenv”

Step 2: Navigate to Your Project Directory

Open your terminal or command prompt and navigate to the directory where you want to create
the virtual environment. Use the cd command to change directories.

Step 3: Create the Virtual Environment

Once you're in the desired directory, run the following command to create a virtual environment
named myenv (you can replace myenv with any name you prefer):

“virtualenv myenv”

This command will create a new directory named myenv in your current directory, which
contains the isolated Python environment.

Step 4: Activate the Virtual Environment

After creating the virtual environment, you need to activate it. Activation sets up your terminal or
command prompt to use the Python interpreter and packages installed within the virtual
environment. The activation command varies depending on your operating system:

● Windows:

myenv\Scripts\activate
macOS/Linux:
source myenv/bin/activate

You'll notice that your command prompt or terminal changes to indicate that you're now working
within the virtual environment, often by displaying the name of the environment at the beginning
of the prompt.

Step 5: Deactivate the Virtual Environment

To deactivate the virtual environment and return to your global Python environment, simply run
the following command:

“deactivate”

Your command prompt or terminal will return to its normal state, indicating that you've exited the
virtual environment.

Installation of Django

Step 1: Open Command Prompt or Terminal

Depending on your operating system, open a command prompt or terminal window.

Step 2: Create a Virtual Environment (Optional but Recommended)

It's a good practice to create a virtual environment for your Django projects to isolate their
dependencies. To create a virtual environment, use the following command:

python -m venv myenv

Replace myenv with the name you want to give to your virtual environment.

Step 3: Activate the Virtual Environment

● On Windows:

myenv\Scripts\activate

On macOS/Linux:

source myenv/bin/activate
Step 4: Install Django

Once your virtual environment is activated, you can use pip to install Django:

pip install Django

This command will download and install the latest version of Django along with its
dependencies.

Step 5: Verify Installation

You can verify that Django is installed correctly by running the following command:

python -m django --version

This should display the installed Django version, confirming that it’s successfully installed.

3. Creating a Django Project

Step 1: Create a Django Project

To create a new Django project, you can use the following command:

django-admin startproject projectname

● Replace projectname with the desired name for your Django project.

This command sets up the basic structure of a Django project, including essential directories
and files like manage.py (a command-line utility) and the project settings file.

Root Directory (Project Folder)

● manage.py: A command-line utility that lets you interact with your Django project. You
can use it to run the development server, start new apps, and interact with the database.
● requirements.txt (optional): A file where you can list all the Python dependencies for
your project. This makes it easier to install them using pip.

Project Package

● This is a directory with the same name as your project, which contains the project's
settings and configuration files.
● init.py: An empty file that indicates this directory should be treated as a Python package.
● settings.py: Contains all the configuration settings for your Django project, including
installed apps, middleware, database settings, and more.
● urls.py: The URL configuration file where you map URL patterns to views. This file
defines the paths available in your project.
● wsgi.py: Used for deploying your project using a WSGI-compatible web server. WSGI
stands for Web Server Gateway Interface.
● asgi.py: Similar to wsgi.py, but used for deploying your project using an
ASGI-compatible web server. ASGI stands for Asynchronous Server Gateway Interface.

Step 2: Run the Development Server

After creating your Django project, you can start the development server to see your application
in action. Navigate to your project's directory using the command line and run:

python manage.py runserver

● This will start the development server on the default port 8000.
● You can access your Django application by opening a web browser and going to
http://127.0.0.1:8000/.

Customizing the Server Port

If you need to run the Django project on a different port, you can specify the port number like
this:

python manage.py runserver 8080

This command starts the server at http://127.0.0.1:8080/.

Important Note: Managing Dependencies


When working on larger projects, it's good practice to manage your project's dependencies in a
requirements.txt file. This file lists all the packages your project depends on, making it
easier for others to set up the project on their machines.

● To generate a requirements.txt file, run:

pip freeze > requirements.txt

Others can install the same dependencies by running:

pip install -r requirements.txt

This practice ensures that all developers working on the project have a consistent
development environment.

4. Difference Between MVC and MVT Templates

MVC (Model-View-Controller) and MVT (Model-View-Template) are architectural patterns


used in web application development. They both aim to separate concerns within an application,
but they have different structures and components, especially in how they manage the flow of
data and user interaction.

Model-View-Controller (MVC)

● Model: Represents the data and business logic of the application. It handles data
manipulation, storage, and retrieval. The model interacts with the database and defines
how data is structured and managed.
● View: Represents the presentation layer. It displays the data to the user and serves as
the user interface. The view presents the data provided by the model in a format that the
user can understand.
● Controller: Acts as an intermediary between the model and the view. It handles user
input, processes it, and updates the model accordingly. The controller also updates the
view when the model changes. It is responsible for interpreting user actions (e.g., clicks,
form submissions) and invoking the appropriate responses.

Key Characteristics of MVC:

● The controller is a crucial component that manages the flow of data between the model
and the view.
● MVC provides a clear separation of concerns, with the controller mediating between the
data (model) and the user interface (view).
● Commonly used in frameworks like Ruby on Rails, ASP.NET MVC, and Spring MVC.
Model-View-Template (MVT)

● Model: Similar to MVC, the model represents the data and business logic of the
application. It interacts with the database and defines how data is structured, validated,
and manipulated.
● View: Represents the presentation layer, similar to the view in MVC. However, in MVT,
the view is often more focused on processing and selecting data to be presented to the
user, leaving the rendering of data to the template.
● Template: Represents the structure of the user interface. Templates are typically HTML
files with placeholders for dynamic data. These placeholders are filled in by the view with
data from the model, allowing for the presentation of dynamic content.

Key Characteristics of MVT:

● In MVT, there's no explicit controller component. Instead, the Django framework itself
handles the routing of requests and delegates tasks to the appropriate view.
● The template plays a central role in defining the structure and presentation of the user
interface, combining static HTML with dynamic content from the model.
● Django automatically manages the flow of control, making it easier to handle user
requests and responses without manually coding a controller.

Summary:

● MVC explicitly defines a controller component to manage the interaction between the
model and view. This separation is useful for larger, more complex applications where
you need granular control over user interaction.
● MVT, used in Django, abstracts away the need for a controller by letting the framework
handle request routing and view selection. The template in MVT is key to defining how
the data is presented, making it easier to manage the user interface and dynamic
content.

While both patterns promote modular architecture and separation of concerns, MVC offers more
explicit control over the flow of data and user interaction, whereas MVT simplifies development
by relying on the framework to manage these aspects.

Django MVT Structure

The Django web framework follows the MVT pattern (Model-View-Template), a variation of the
MVC (Model-View-Controller) pattern. The MVT pattern is tailored to Django's design
philosophy and conventions, providing a streamlined and efficient way to develop web
applications. Below is an explanation of how Django implements the MVT structure:

1. Model
● Definition: In Django, the model represents the data structure and business logic of the
application. Models are typically defined as Python classes, where each class
corresponds to a table in the database. These classes define the fields and behaviors of
the data entities in the application.
● Object-Relational Mapping (ORM): Django's ORM allows developers to interact with
the database using Python objects, abstracting away the details of writing raw SQL
queries. This makes it easier to perform CRUD (Create, Read, Update, Delete)
operations and manage database relationships.
● Location: Models are defined in the models.py file within each Django app. For
example:

from django.db import models

class Author(models.Model):
name = models.CharField(max_length=100)
birthdate = models.DateField()

2. View

● Definition: In Django, the view is responsible for handling user requests and generating
the appropriate response. Views are Python functions or classes that receive HTTP
requests, process them, and return HTTP responses.
● Interaction with Models: Views often interact with models to retrieve or manipulate data
before rendering a response. They serve as the intermediary between the model (data)
and the template (presentation).
● Types of Views: Django provides both function-based views (FBVs) and class-based
views (CBVs). FBVs are simpler and more straightforward, while CBVs offer more
structure and reusability through inheritance and mixins.
● Location: Views are defined in the views.py file within each Django app. For example:

from django.shortcuts import render


from .models import Author

def author_list(request):
authors = Author.objects.all()
return render(request, 'authors.html', {'authors': authors})

3. Template
● Definition: The template in Django represents the presentation layer of the application.
It defines the structure and layout of the HTML pages that are sent to the client.
Templates contain static parts of the desired HTML output as well as placeholders for
dynamic content.
● Django Template Language (DTL): Django templates use the Django Template
Language, which allows developers to embed logic like variables, loops, and
conditionals directly into HTML. This makes it easy to dynamically generate content
based on the data passed from the view.
● Location: Templates are typically stored in the templates directory within a Django
app. The template files usually have an .html extension. For example:

<!-- authors.html -->


<h1>Authors</h1>
<ul>
{% for author in authors %}
<li>{{ author.name }} - Born on {{ author.birthdate }}</li>
{% endfor %}
</ul>

Request-Response Cycle in Django MVT

1. Request Handling: A user makes a request to a URL that is routed to a Django view.
2. View Processing: The view processes the request, interacts with the model layer to
fetch or manipulate data as necessary, and prepares the data to be displayed.
3. Template Rendering: The view renders a template, passing the processed data to it.
The template uses this data to generate an HTML page.
4. Response: The rendered HTML page is sent as a response to the user's browser,
where it is displayed.

Summary:

● The Model handles the business logic and database interactions.


● The View processes requests and prepares data for rendering.
● The Template is responsible for presenting the data in a structured and user-friendly
format.

Django's MVT pattern emphasizes a clean separation of concerns, making it easier to manage
and maintain your web application. By leveraging Django's powerful ORM, flexible view system,
and dynamic templates, you can build robust and scalable web applications with minimal
boilerplate code.
5. Creating an Application in Django

Creating an app in Django is a fundamental step in building a modular and organized web
application. An app in Django is a self-contained module that can be reused across different
projects. Below are the steps to create and integrate an app into your Django project:

1. Navigate to Your Project Directory

First, navigate to the directory of your Django project using the cd command. This ensures that
you’re working within the correct project context.

cd projectname

2. Create a New App

To create a new app within your Django project, use the following command. This will generate
the necessary directory structure and files for your app:

python manage.py startapp appname

Replace appname with the name of your app. This command will create a directory structure
similar to the following:

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

Apps

● Django projects are organized into multiple applications (apps), each of which is a
self-contained module with its own functionality.
● Each app typically has the following structure:
○ models.py: Defines the data models for your app, which Django uses to create
database tables.
○ views.py: Contains the view functions or classes that process requests and
return responses.
○ urls.py: (Optional) Used for defining URL patterns specific to the app.
○ admin.py: Registers models with the Django admin site, allowing you to manage
them via a web interface.
○ apps.py: Contains the app configuration, which can include metadata and
settings specific to the app.
○ migrations/: A folder that contains migration files, which are used to alter the
database schema based on your models.
○ static/: A folder for storing static files like CSS, JavaScript, and images used by
the app.
○ templates/: A folder for storing HTML template files that are rendered by your
views.
○ tests.py: A file for writing tests to ensure your app functions as expected.

3. Configure Your App in settings.py

Next, you need to inform Django about your new app by adding it to the INSTALLED_APPS list
in your project’s settings.py file:

# projectname/settings.py

INSTALLED_APPS = [
# ...
'appname',
]

This step ensures that Django recognizes your app and includes it in the project.

4. Define Models

In your app’s models.py file, define the data models that your app will use. Django’s
Object-Relational Mapping (ORM) system allows you to define your data structure as Python
classes, which are automatically translated into database tables.

# appname/models.py
from django.db import models
class YourModel(models.Model):
field1 = models.CharField(max_length=100)
field2 = models.IntegerField()

def __str__(self):
return self.field1

5. Create Migrations

To create the necessary database migrations for your models, run the following command:

python manage.py makemigrations appname

This command generates migration files that describe the changes you made to your models.

6. Apply Migrations

Apply the migrations to create the corresponding database tables:

python manage.py migrate

This will execute the migrations and update your database schema.

7. Create Views, Templates, and URLs

Now, you can start building the user interface and logic for your app:

● Views: Define the logic that handles user requests in your app’s views.py.
● Templates: Create HTML templates in a templates directory inside your app directory.
● URLs: Define the URL patterns for your app in urls.py.

For example, in views.py:

# appname/views.py
from django.shortcuts import render

def homepage(request):
return render(request, 'homepage.html')

In urls.py:
# appname/urls.py
from django.urls import path
from . import views

urlpatterns = [
path('', views.homepage, name='homepage'),
]

8. Connect URLs to Your App

In your project’s urls.py, include the URLs of your app using the include function:

# projectname/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('appname/', include('appname.urls')), # Include app-specific URLs here
]

This step connects your app's URLs to the main project’s URL configuration.

9. Run the Development Server

Start the Django development server to test your app:

python manage.py runserver

10. Access Your App

Open a web browser and navigate to http://localhost:8000/appname/ (replace


appname with your app’s name) to see your app in action.

Summary

You've now successfully created and integrated an app into your Django project. This process
includes setting up models, views, templates, and URLs. You can continue to develop your app
by adding more features, views, templates, and other functionalities as needed. By organizing
your project into separate apps, you maintain a clean and scalable codebase, making it easier
to manage and extend in the future.

6. Understanding the Django Project Folder Structure

A Django project is organized into a specific directory structure that helps manage different
components of the application efficiently. Below is an overview of the typical contents of a
Django project folder and the role each part plays.

Project Configuration Files

1. manage.py:
○ Purpose: This is a command-line utility that interacts with your Django project. It
allows you to run development servers, create database tables, manage
applications, run tests, take backups of fixtures, create superusers, open Django
shells, and perform various other administrative tasks.
○ Common Commands:
■ python manage.py runserver — Start the development server.
■ python manage.py migrate — Apply database migrations.
■ python manage.py createsuperuser — Create an admin user.
■ python manage.py shell — Open an interactive Python shell.

Project Settings

The settings.py file in Django serves as the central configuration hub for the entire project.
Here’s an overview of the key settings found in this file:

1. Database Configuration:
○ Purpose: Defines the database connections for your project.
○ Commonly Configured Databases:
■ SQLite (default): Requires no additional configuration.
■ MySQL: Requires installation of mysqlclient (pip install
mysqlclient).
■ PostgreSQL: Requires installation of psycopg2 (pip install
psycopg2).
○ Parameters: To connect to databases like MySQL or PostgreSQL, you need to
specify additional parameters:
■ ENGINE, NAME, USER, PASSWORD, HOST, PORT.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydatabase',
'USER': 'myuser',
'PASSWORD': 'mypassword',
'HOST': 'localhost',
'PORT': '5432',
}
}

Debug Mode:

● Purpose: Controls whether Django operates in debug mode.


● Usage:
○ DEBUG = True during development for detailed error messages.
○ DEBUG = False in production for better performance and security.

Installed Apps:

● Purpose: Lists all the Django apps that are installed in your project.
● Example:

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp', # Your custom app
]

Middleware:

● Purpose: Middleware classes process requests and responses globally before they
reach the view or after they leave the view.
● Common Middleware:
○ SecurityMiddleware
○ SessionMiddleware
○ CommonMiddleware
○ CsrfViewMiddleware
○ AuthenticationMiddleware

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
]

Static Files:

● Purpose: Handles static files like CSS, JavaScript, and images.


● Settings:
○ STATIC_URL: Base URL for serving static files.
○ STATICFILES_DIRS: Additional directories to search for static files

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

Template Configuration:

● Purpose: Defines how templates are managed in Django.


● Components:
○ DIRS: List of directories where Django looks for templates.
○ APP_DIRS: If True, Django will look for templates in each app's templates
subdirectory.

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

Internationalization and Localization:

● Purpose: Supports multiple languages and regional formats.


● Key Settings:
○ LANGUAGE_CODE: Default language for the project.
○ TIME_ZONE: Default time zone.
○ USE_I18N: Enable/disable Django’s translation system.
○ USE_L10N: Enable/disable localized formatting of data.
○ USE_TZ: Enable/disable time zone support.

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True

Security Settings:

● Purpose: Configures various security-related aspects of the project.


● Examples:
○ SECRET_KEY: Used for cryptographic signing.
○ SECURE_BROWSER_XSS_FILTER: Enables the browser's XSS protection.
○ SECURE_CONTENT_TYPE_NOSNIFF: Prevents the browser from interpreting files
as a different MIME type.

CREATING AN HELLO WORLD PROGRAM IN DJANGO:


Creating a "Hello World" program in Django is a great way to get started with the framework.
Here's how you can do it step by step:

1. Install Django

If you haven't already, install Django using pip:

pip install django

2. Create a Django Project

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

django-admin startproject helloworld

This will create a directory named helloworld with the basic Django project structure.

3. Create a Django App

Navigate into the project directory and create a new app:

cd helloworld
python manage.py startapp myapp

This will create a new directory myapp within your project, where you'll build the "Hello World"
functionality.

4. Configure the App in settings.py

Open the settings.py file located in the helloworld/helloworld directory and add
myapp to the INSTALLED_APPS list:

INSTALLED_APPS = [
...
'myapp',
]
5. Create a View

In myapp/views.py, create a simple view function that returns an HTTP response with "Hello,
World!":

from django.http import HttpResponse

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

6. Define a URL Pattern

Create a urls.py file inside the myapp directory (if it doesn't already exist), and define a URL
pattern for your view:

from django.urls import path


from . import views

urlpatterns = [
path('', views.hello_world, name='hello_world'),
]

7. Include the App's URL in the Project URL Configuration

Open the helloworld/urls.py file in the project directory and include the myapp URLs:

from django.contrib import admin


from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('myapp.urls')), # Include the app's URL patterns
]

8. Run the Development Server


Start the Django development server to see your "Hello World" program in action:

python manage.py runserver

9. View the Result

Open your web browser and go to http://127.0.0.1:8000/. You should see the text
"Hello, World!" displayed on the screen.

That's it! You've created a basic "Hello World" program in Django. This simple example shows
how to set up a Django project, create an app, and map a view to a URL.

SECTION 2: DATABASE AND VIEWS

Custom User Model

In Django, customizing the user model allows you to extend or modify the default authentication
system to suit your application's needs.

1. Import Necessary Modules:


In your models.py file, begin by importing the required modules:

from django.contrib.auth.models import AbstractUser, BaseUserManager


from django.db import models

Create a Custom User Manager:

A custom manager allows you to define methods for creating users, including additional logic or
constraints. Although optional, it's often a good practice to define a custom manager when
working with a custom user model.

class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('The Email field must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)

if extra_fields.get('is_staff') is not True:


raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')

return self.create_user(email, password, **extra_fields)

Create a Custom User Model:

Subclass the AbstractUser class to create your custom user model. In this example, we'll use
the email field as the unique identifier for authentication instead of the username.

class CustomUser(AbstractUser):
email = models.EmailField(unique=True)
# Add any additional fields you want here

# Override the username field to use email for authentication


username = None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []

objects = CustomUserManager()

def __str__(self):
return self.email

In this custom user model:

● The email field is set to be unique, ensuring that each user has a distinct email
address.
● The username field is removed, and email is used as the USERNAME_FIELD for
authentication.
● REQUIRED_FIELDS is left empty because we only require the email and password for
user creation.
Connecting the Custom User Model to the Admin Panel:
After defining the custom user model, make sure to update your settings.py to use it:

AUTH_USER_MODEL = 'yourappname.CustomUser'

This line tells Django to use your custom user model instead of the default one.

Once we have done with the customized user model lets us see how to create a user signup
and login view for that.

To create a signup and login functionality using Django with two different views, you can follow
these steps:

1. Create a Signup View

First, create a view that allows users to sign up by providing their email and password.

from django.shortcuts import render, redirect


from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages

# Import the custom user model


User = get_user_model()

def signup_view(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Account created successfully. You can now log in.")
return redirect('login') # Redirect to the login page after successful signup
else:
form = UserCreationForm()

return render(request, 'signup.html', {'form': form})

2. Create a Login View

Next, create a view that allows users to log in using their email and password.
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib import messages

def login_view(request):
if request.method == 'POST':
email = request.POST['email']
password = request.POST['password']
user = authenticate(request, username=email, password=password)
if user is not None:
login(request, user)
messages.success(request, "You have successfully logged in.")
return redirect('home') # Redirect to the homepage or dashboard after
successful login
else:
messages.error(request, "Invalid email or password. Please try again.")

return render(request, 'login.html')

3. Create Templates for Signup and Login

You will need to create simple HTML templates for signup and login forms. Here are basic
examples:

signup.html

<!DOCTYPE html>
<html>
<head>
<title>Sign Up</title>
</head>
<body>
<h2>Sign Up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign Up</button>
</form>
<p>Already have an account? <a href="{% url 'login' %}">Login here</a></p>
</body>
</html>

Login.html:

<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form method="post">
{% csrf_token %}
<label for="email">Email:</label>
<input type="email" name="email" required><br><br>
<label for="password">Password:</label>
<input type="password" name="password" required><br><br>
<button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="{% url 'signup' %}">Sign up here</a></p>
</body>
</html>

4. Update urls.py

Finally, add URL patterns for the signup and login views in your app's urls.py:

from django.urls import path


from .views import signup_view, login_view

urlpatterns = [
path('signup/', signup_view, name='signup'),
path('login/', login_view, name='login'),
]
5. Customizing UserCreationForm (Optional)

If you're using a custom user model with an email field, you might want to customize the
UserCreationForm to include the email field instead of the default username. Here's an
example:

from django import forms


from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model

class CustomUserCreationForm(UserCreationForm):
email = forms.EmailField(required=True)

class Meta:
model = get_user_model()
fields = ("email",)

def save(self, commit=True):


user = super().save(commit=False)
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user

Then, update the signup_view to use CustomUserCreationForm:

def signup_view(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Account created successfully. You can now log in.")
return redirect('login')
else:
form = CustomUserCreationForm()

return render(request, 'signup.html', {'form': form})


Generating Responses in Django

Django provides various ways to generate HTTP responses based on the requirements of your
application. Below are some common response types that you might use in Django:

I) HttpResponse

The most straightforward way to generate an HTTP response in Django is by using the
HttpResponse class. This class allows you to create an HttpResponse object with the
content you want to send as the response. You can also set HTTP headers and status codes as
needed.

Example:

from django.http import HttpResponse

def my_view(request):
response = HttpResponse("Hello, World!", content_type="text/plain")
response.status_code = 200
response['Custom-Header'] = 'Header Value'
return response

In this example:

● content_type specifies the MIME type of the response content.


● status_code sets the HTTP status code.
● Custom-Header is an example of setting custom HTTP headers.

II) Rendered Templates

Often, you'll want to render HTML templates and return them as responses. Django provides the
render function to simplify this process. You can define HTML templates using Django's
template language and then render them with context data to generate dynamic HTML.

Example:

from django.shortcuts import render


def my_view(request):
context = {'variable': 'value'}
return render(request, 'template_name.html', context)

In this example:

● The context dictionary is passed to the template, allowing you to insert dynamic
content.

III) JSON Responses

When working with AJAX or building APIs, you may need to return JSON responses. Django's
JsonResponse class makes it easy to create JSON responses.

Example:

from django.http import JsonResponse

def json_view(request):
data = {'key': 'value'}
return JsonResponse(data)

Example with User Data:

from django.http import JsonResponse


from .models import User

def user_view(request):
user_data = list(User.objects.all().values())
return JsonResponse(user_data, safe=False)

In this example:

● safe=False allows you to return a non-dict object, like a list.

IV) Redirects
To redirect users to another URL, you can use the redirect function.

Example:

from django.shortcuts import redirect

def redirect_view(request):
return redirect('new_url')

Example with External URL:

def redirect_urls(request):
return redirect("http://localhost:8080/token/userdetails")

V) TemplateResponse

TemplateResponse allows you to render a template and return it as an HttpResponse. This


can be useful for complex views where the template rendering might depend on certain
conditions.

Example:

from django.template.response import TemplateResponse

def my_template_view(request):
context = {'name': 'John Doe'}
return TemplateResponse(request, 'my_template.html', context)

VI) FileResponse

FileResponse is used to serve files efficiently as HTTP responses. This is particularly useful
for serving large files, such as images, PDFs, or other downloadable content, as it streams the
file to the client without loading the entire file into memory.

Example: Serving a PDF File

from django.http import FileResponse


def serve_file(request):
file_path = '/path/to/your/file.pdf'
response = FileResponse(open(file_path, 'rb'))
response['Content-Type'] = 'application/pdf'
response['Content-Disposition'] = 'attachment; filename="your_file.pdf"'
return response

Example: Serving an Image File

from django.http import FileResponse

def serve_image(request):
file_path = '/home/user/Pictures/shiva/shiva4.jpg'
response = FileResponse(open(file_path, 'rb'))
response['Content-Type'] = 'image/jpeg'
response['Content-Disposition'] = 'attachment; filename="shiva_pics.jpg"'
return response

In these examples:

● file_path should point to the location of the file you want to serve.
● Content-Type specifies the type of content being served.
● Content-Disposition suggests how the browser should handle the file, with
attachment indicating that the file should be downloaded rather than displayed inline.

Django Rest Framework (DRF) Responses

In Django Rest Framework, generating responses is straightforward and flexible. DRF’s


Response class automatically handles content rendering into the appropriate format (like
JSON) based on the client's request. Below are different ways to work with responses in DRF:

1. Basic Response

The simplest way to return a response in DRF is by using the Response class from
rest_framework.response.
Example:

from rest_framework.response import Response


from rest_framework.decorators import api_view

@api_view(['GET'])
def example_view(request):
data = {
'message': 'Hello, World!',
'status': 'success'
}
return Response(data)

In this example:

● The Response class is used to return a response, which is automatically rendered as


JSON (or another appropriate format based on the request).

2. Setting HTTP Status Codes

You can specify HTTP status codes using the status module from rest_framework.

Example:

from rest_framework.response import Response


from rest_framework import status
from rest_framework.decorators import api_view

@api_view(['POST'])
def create_item(request):
if request.method == 'POST':
# Perform creation logic here
data = {'message': 'Item created successfully'}
return Response(data, status=status.HTTP_201_CREATED)
else:
data = {'message': 'Invalid request method'}
return Response(data, status=status.HTTP_400_BAD_REQUEST)
In this example:

● status.HTTP_201_CREATED and status.HTTP_400_BAD_REQUEST are used to


return appropriate HTTP status codes.

3. Custom Headers

You can customize the response by setting custom headers.

Example:

from rest_framework.response import Response


from rest_framework.decorators import api_view

@api_view(['GET'])
def custom_header_view(request):
data = {'message': 'Hello with custom headers'}
response = Response(data)
response['X-Custom-Header'] = 'Custom value'
return response

In this example:

● X-Custom-Header is an example of adding a custom HTTP header to the response.

4. Handling Errors Gracefully

DRF provides a way to handle errors gracefully using custom error responses.

Example:

from rest_framework.response import Response


from rest_framework import status
from rest_framework.exceptions import NotFound

@api_view(['GET'])
def item_detail(request, item_id):
try:
# Assume get_item is a function that retrieves an item by id
item = get_item(item_id)
data = {'item': item}
return Response(data)
except Item.DoesNotExist:
raise NotFound(detail="Item not found", code=404)

In this example:

● The NotFound exception is used to return a 404 response with a custom message.

5. Content Negotiation

DRF can return responses in different formats like JSON, XML, etc. The format is automatically
negotiated based on the client's request.

Example:

from rest_framework.decorators import api_view


from rest_framework.response import Response

@api_view(['GET'])
def example_view(request):
data = {
'message': 'Hello, World!',
'status': 'success'
}
return Response(data)

In this example:

● The response format is determined by the Accept header in the client's request (e.g.,
application/json, application/xml).

6. Working with Serializers and APIView

When working with serializers, APIView allows for more complex operations with DRF.
Example:

from rest_framework.views import APIView


from rest_framework.response import Response
from .serializers import ProductSerializer
from .models import Product

class SampleView(APIView):

def get(self, request):


data = Product.objects.all()
# Pass 'many=True' to serialize a queryset
response = ProductSerializer(data, many=True).data
return Response({"data": response})

def post(self, request):


serializer = ProductSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({"message": "Product created successfully", "data":
serializer.data})
return Response(serializer.errors, status=400)

In this example:

● ProductSerializer is used to serialize the data from the Product model.


● The APIView class is used to handle both GET and POST requests, making it easy to
manage data retrieval and creation in a single view.

Handling Requests with Django Rest Framework

Using Django Rest Framework (DRF) allows you to handle various HTTP methods (GET, POST,
PUT, PATCH, DELETE) in a simplified and structured way. Here’s an example:

Create a Model

Assume we have a simple model called Book:


from django.db import models

class Book(models.Model):

title = models.CharField(max_length=100)

author = models.CharField(max_length=100)

published_date = models.DateField()

def __str__(self):

return self.title

Create a Serializer

Serializers in DRF are used to convert model instances into JSON format and vice versa:

from rest_framework import serializers

from .models import Book

class BookSerializer(serializers.ModelSerializer):

class Meta:

model = Book

fields = '__all__'

Create Views to Handle Requests


You can create a APIView or use ViewSets to handle different HTTP methods.

Using APIView

from rest_framework.views import APIView

from rest_framework.response import Response

from rest_framework import status

from .models import Book

from .serializers import BookSerializer

class BookListCreateView(APIView):

def get(self, request):

books = Book.objects.all()

serializer = BookSerializer(books, many=True)

return Response(serializer.data)

def post(self, request):

serializer = BookSerializer(data=request.data)

if serializer.is_valid():

serializer.save()

return Response(serializer.data, status=status.HTTP_201_CREATED)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class BookDetailView(APIView):

def get(self, request, pk):


book = Book.objects.get(pk=pk)

serializer = BookSerializer(book)

return Response(serializer.data)

def put(self, request, pk):

book = Book.objects.get(pk=pk)

serializer = BookSerializer(book, data=request.data)

if serializer.is_valid():

serializer.save()

return Response(serializer.data)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def delete(self, request, pk):

book = Book.objects.get(pk=pk)

book.delete()

return Response(status=status.HTTP_204_NO_CONTENT)

Using ViewSets

ViewSets allow you to define behavior for a model in a single class:

from rest_framework import viewsets


from .models import Book
from .serializers import BookSerializer

class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
Step 6: Configure URLs

To wire these views into your URLs, you need to update urls.py:

For APIView

from django.urls import path


from .views import BookListCreateView, BookDetailView

urlpatterns = [
path('books/', BookListCreateView.as_view(), name='book-list-create'),
path('books/<int:pk>/', BookDetailView.as_view(), name='book-detail'),
]

For ViewSets (Using Routers)

from django.urls import path, include


from rest_framework.routers import DefaultRouter
from .views import BookViewSet

router = DefaultRouter()
router.register(r'books', BookViewSet)

urlpatterns = [
path('', include(router.urls)),
]

Models and Admin Page in Django

Models:

In Django, models are a core component of the Object-Relational Mapping (ORM) system. They
define the structure of your application's database tables and provide an abstraction layer for
interacting with the database. Models allow you to work with data in a more Pythonic way, using
Python classes and objects instead of writing raw SQL queries.

Creating a Model Class:


To define a model, you create a Python class that inherits from django.db.models.Model.
This class represents a database table, and each attribute (field) in the class corresponds to a
column in the table.

Example:

from django.db import models

class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
age = models.IntegerField()

Fields in Django Models:

In Django, each model field defines a column in the database table. Below is an overview of
common field types you can use in Django models:

CharField:

○ Purpose: Used for short text fields (e.g., names, titles).


○ Parameters: max_length to specify the maximum number of characters.
○ Example:

title = models.CharField(max_length=100)

TextField:

● Purpose: Used for longer text fields (e.g., descriptions, comments).


● Example

description = models.TextField()

IntegerField:

● Purpose: Used for integer values.


● Example

price = models.FloatField()
FloatField:

● Purpose: Used for floating-point numbers.


● Example

price = models.FloatField()

DateField:

● Purpose: Used for date values.


● Parameters: auto_now, auto_now_add, or default.
● Example

birthdate = models.DateField()

TimeField:

● Purpose: Used for time values.


● Parameters: auto_now, auto_now_add, or default.

appointment_time = models.TimeField()

DateTimeField:

● Purpose: Used for date and time values.


● Parameters: auto_now, auto_now_add, or default.

created_at = models.DateTimeField(auto_now_add=True)

BooleanField:

● Purpose: Used for boolean values (True/False).


● Example

is_active = models.BooleanField(default=True)

EmailField:

● Purpose: Used for email addresses.


● Example

email = models.EmailField(max_length=100)

URLField:

● Purpose: Used for URLs.


● Example:

website = models.URLField(max_length=200)

ImageField and FileField:

● Purpose: Used for uploading images or files.


● Parameters: upload_to, null, and blank.
● Example

image = models.ImageField(upload_to='images/')
document = models.FileField(upload_to='documents/', null=True, blank=True)

ForeignKey:

● Purpose: Used to establish a many-to-one or one-to-one relationship with another


model.
● Example

author = models.ForeignKey(Author, on_delete=models.CASCADE)

Additional Field Types:

AutoField:

○ An integer field that automatically increments. Usually, this is automatically added


if no primary key is specified.
○ Example:

id = models.AutoField(primary_key=True)

SlugField:

● A field for storing URL slugs, often used for SEO-friendly URLs.
● Example:
slug = models.SlugField(max_length=50)

BigIntegerField:

● A field for storing large integer values.


● Example

large_number = models.BigIntegerField()

PositiveIntegerField:

● A field for storing positive integers.


● Example

positive_number = models.PositiveIntegerField()

DecimalField:

● A field for storing fixed-precision decimal numbers. Requires max_digits and


decimal_places parameters.
● Example

price = models.DecimalField(max_digits=10, decimal_places=2)

OneToOneField:

● A field for creating a one-to-one relationship.


● Example

profile = models.OneToOneField(User, on_delete=models.CASCADE)

ManyToManyField:

● A field for creating a many-to-many relationship.


● Example

categories = models.ManyToManyField(Category)

JSONField:

● A field for storing JSON-encoded data.


● Example

metadata = models.JSONField()

Model Attributes:

In Django models, the @property decorator is often used to define dynamic, computed
attributes based on the model’s fields. These attributes are accessible like normal fields, but
their values are computed dynamically.

Example

from django.db import models

from datetime import date

class Person(models.Model):

first_name = models.CharField(max_length=50)

last_name = models.CharField(max_length=50)

birth_date = models.DateField()

@property

def full_name(self):

return f"{self.first_name} {self.last_name}"

@property

def age(self):

return date.today().year - self.birth_date.year


Using the Property:

Once defined, these properties can be accessed as if they were regular attributes of the model
instance.

Example Usage:

person = Person(first_name='John', last_name='Doe', birth_date='1990-01-01')

# Accessing the properties

print(person.full_name) # Output: John Doe

print(person.age) # Output: The computed age based on birth_date

Benefits of Using @property:

1. Encapsulation: Control access to an attribute and add logic to the getter method without
changing the interface.
2. Readability: Access methods like attributes, making the code more readable.
3. Dynamic Computation: Compute values dynamically based on other fields or logic.

By default, properties created with @property are read-only. If you try to assign a value to
them, an error will be raised:

person.full_name = "Jane Doe" # This will raise an AttributeError

Example of Relationships with ForeignKey:

In the example below, we define two models: Author and Book. The Book model has a foreign
key field author that establishes a one-to-many relationship with the Author model. This
means one author can be associated with multiple books, but each book is associated with only
one author.

class Author(models.Model):

name = models.CharField(max_length=100)

class Book(models.Model):
title = models.CharField(max_length=100)

author = models.ForeignKey(Author, on_delete=models.CASCADE)

Django ORM (Object-Relational Mapper)


Overview
Creating Related Records
One-to-Many Relationship

# Create an author instance

author = Author.objects.create(name="John Doe")

# Create book instances linked to the author

book1 = Book.objects.create(title="Book 1", author=author)

book2 = Book.objects.create(title="Book 2", author=author)

● Explanation: This example demonstrates how to associate an Author instance with


multiple Book instances using a ForeignKey. Each Book is linked to one Author,
establishing a one-to-many relationship.

Accessing Related Records


From Author to Book (One-to-Many)
author = Author.objects.get(name="John Doe")

books_by_author = author.book_set.all()

● Explanation: The book_set attribute is automatically created by Django for reverse


relationships. It allows access to all Book instances associated with a specific Author.

From Book to Author (Many-to-One)

book = Book.objects.get(title="Book 1")

author_of_book = book.author

# Querying with filter

Book.objects.filter(id=2).values('author__name')

● Explanation: The author attribute in the Book model allows access to the Author
associated with a specific Book. The query with filter demonstrates how to retrieve
an author's name directly.

Deleting Related Records


class Book(models.Model):

title = models.CharField(max_length=100)

author = models.ForeignKey(Author, on_delete=models.SET_NULL, null=True)

● Explanation: The on_delete argument in ForeignKey defines behavior when the


related Author is deleted. Using models.SET_NULL sets the author field to None
instead of deleting the Book.
Many-to-Many Relationships

from django.db import models

class Author(models.Model):

name = models.CharField(max_length=100)

class Book(models.Model):

title = models.CharField(max_length=100)

authors = models.ManyToManyField(Author)

● Explanation: ManyToManyField is used to create a many-to-many relationship


between Author and Book. This means multiple Author instances can be linked to
multiple Book instances.

Adding Authors to a Book

book = Book.objects.create(title="Sample Book")

author1 = Author.objects.create(name="Author 1")

author2 = Author.objects.create(name="Author 2")

book.authors.add(author1, author2)

● Explanation: The add method associates multiple Author instances with a Book.
Retrieving Books by Authors

books_by_author1 = Book.objects.filter(authors__name="Author 1")

authors_of_book = book.authors.all()

● Explanation: You can filter books by an author's name and retrieve all authors
associated with a book.

Removing Authors from a Book

book.authors.remove(author1)

● Explanation: The remove method removes the relationship between the Book and the
Author without deleting either.

Advanced Query Examples

from django.db.models import Avg, Count

genre_average_ratings =
Book.objects.filter(pub_date__gte="2020-01-01").values('genre').annotate(

average_rating=Avg('rating'),

book_count=Count('id')

for genre in genre_average_ratings:

print(f"Genre: {genre['genre']} - Average Rating: {genre['average_rating']:.2f}


({genre['book_count']} books)")
● Explanation: This example demonstrates how to group books by genre, calculate
average ratings, and count the number of books using Django's annotate, Avg, and
Count functions.

Real-World Example

res1 =
OrganistaionUserRespondentResponse.filterAll(user_assessment__id__in=data["team_assess
ment_id"],
is_participant=True).values("assessment_question__attribute__attribute_name").annotate(rating
=Avg('assessment_value'))

● Explanation: This is a real-world query that aggregates ratings for different assessment
attributes.

One-to-One Relationships
from django.db import models

class Person(models.Model):

first_name = models.CharField(max_length=30)

last_name = models.CharField(max_length=30)

class UserProfile(models.Model):

person = models.OneToOneField(Person, on_delete=models.CASCADE)

bio = models.TextField()

● Explanation: OneToOneField creates a one-to-one relationship between Person and


UserProfile. Each Person has exactly one UserProfile.
Creating Related Records

person = Person.objects.create(first_name="John", last_name="Doe")

user_profile = UserProfile.objects.create(person=person, bio="A short bio.")

● Explanation: This example creates a Person and links it to a UserProfile.

Accessing Related Records

person = Person.objects.get(first_name="John")

user_profile = person.userprofile

user_profile = UserProfile.objects.get(bio="A short bio.")

person = user_profile.person

● Explanation: The one-to-one relationship allows easy access between Person and
UserProfile.

Creating Database Tables

# Generate migration files based on model changes

python manage.py makemigrations

# Apply migrations to create database tables

python manage.py migrate


Working with Models
Creating Records

person = Person.objects.create(first_name='John', last_name='Doe', age=30)

Querying Data:

people = Person.objects.filter(age__gt=25)

person = Person.objects.get(pk=1)

Updating and Deleting Records:

person.age = 31

person.save()

person.delete()

ORM (Object-Relational Mapping) queries on Django models, which includes various


operations like creating instances, filtering, ordering, and working with relationships. Here's a
breakdown of the key concepts and operations:

1. Creating Models

● Blog, Author, and Entry classes are defined in models.py using Django's
models.Model base class.
● Blog contains fields for name and tagline.
● Author contains fields for name and email.
● Entry contains fields like blog (ForeignKey to Blog), headline, body_text,
pub_date, mod_date, and a ManyToManyField authors linked to the Author model.
Creating Instances in Django Shell:

from User.models import Blog, Entry, Author

b1 = Blog.objects.create(name="xyz", tagline="testtag")
a1 = Author.objects.create(name="william")
e1 = Entry.objects.create(headline="williambook", blog=b1)
e1.authors.add(a1)

Updating and Filtering Entries

● Updating

e1.name = "elmname"
e1.save()

● Filtering

Entry.objects.filter(id=1).values()
Entry.objects.filter(name__startswith="elm").values()
Entry.objects.filter(name__endswith="me").values()
Entry.objects.filter(name__icontains="nam").values()

4. Date Filtering

import datetime

Entry.objects.filter(pub_date__gte=datetime.date.today()).values()
Entry.objects.filter(pub_date__lte=datetime.date.today()).values()

5.Slicing and Ordering

Entry.objects.all()[:2]
Entry.objects.all().order_by("name")

6. Case-Sensitive and Case-Insensitive Queries

● Case-sensitive

Entry.objects.get(headline__contains="Lennon")
Case-insensitive

Entry.objects.filter(headline__icontains="lennon")

7. ForeignKey Filtering

Entry.objects.filter(blog__name="Beatles Blog")

8.Exclusion and Comparison Queries:

Blog.objects.exclude(entry__headline__contains="Lennon",
entry__pub_date__year=2008)
Entry.objects.filter(number_of_comments__gt=F("number_of_pingbacks"))

9. Aggregation and Subqueries

from django.db.models import OuterRef, Subquery, Sum

Entry.objects.values("pub_date__year").annotate(
top_rating=Subquery(
Entry.objects.filter(pub_date__year=OuterRef("pub_date__year"))
.order_by("-rating")
.values("rating")[:1]
),
total_comments=Sum("number_of_comments"),
)

10. Primary Key Lookup

Blog.objects.get(pk=14)

11. JSONField Handling

● Storing and querying JSON data:

from django.db import models

class Dog(models.Model):
name = models.CharField(max_length=200)
data = models.JSONField(null=True)
Key and Path Transforms:

Dog.objects.filter(data__owner__name="Bob")
Dog.objects.filter(data__owner__other_pets__0__name="Fishy")

Caching in QuerySets

● QuerySets cache their results upon evaluation but are not cached when sliced or
indexed unless fully evaluated first.

queryset = Entry.objects.all()
print([p.headline for p in queryset]) # Caches the queryset
print(queryset[5]) # Uses cache

13. Using KT for JSONField

● KT (Key Transform) is used to work with JSON data keys and indexes in queries.

from django.db.models.fields.json import KT

Dogs.objects.annotate(
first_breed=KT("data__breed__1"), owner_name=KT("data__owner__name")
).filter(first_breed__startswith="lhasa", owner_name="Bob")

Here are the revised notes on Django ORM queries, focusing on containment and key lookups,
as well as complex queries with Q objects:

Containment and Key Lookups

Example Data and Setup

# Create sample Dog objects with JSONField data


Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
Dog.objects.create(name="Fred", data={})
contains Lookup

This lookup checks if a key-value pair is present in the JSONField data.

# Query dogs where the owner is Bob


Dog.objects.filter(data__contains={"owner": "Bob"})
# Returns: [<Dog: Rufus>, <Dog: Meg>]

# Query dogs where the breed is collie


Dog.objects.filter(data__contains={"breed": "collie"})
# Returns: [<Dog: Meg>]

contained_by Lookup

This is the inverse of the contains lookup. It returns objects where the key-value pairs on the
object are a subset of the value passed.

# Query dogs where the data is a subset of {"breed": "collie", "owner": "Bob"}
Dog.objects.filter(data__contained_by={"breed": "collie", "owner": "Bob"})
# Returns: [<Dog: Meg>, <Dog: Fred>]

# Query dogs where the data is a subset of {"breed": "collie"}


Dog.objects.filter(data__contained_by={"breed": "collie"})
# Returns: [<Dog: Fred>]

has_key Lookup

This lookup returns objects where the given key exists in the top level of the JSONField.

# Query dogs that have an "owner" key


Dog.objects.filter(data__has_key="owner")
# Returns: [<Dog: Meg>]

has_any_keys Lookup

This lookup returns objects where any of the given keys are present in the top level of the
JSONField.
# Query dogs that have either "owner" or "breed" keys
Dog.objects.filter(data__has_any_keys=["owner", "breed"])
# Returns: [<Dog: Rufus>, <Dog: Meg>]

Complex Lookups with Q Objects

Using Q for Complex Queries

Q objects allow for more complex queries, such as using OR conditions or negating conditions.

from django.db.models import Q

# Query entries that start with "Who" or "What"


Q(question__startswith="Who") | Q(question__startswith="What")
# Equivalent SQL: WHERE question LIKE 'Who%' OR question LIKE 'What%'

# Query entries where question starts with "Who" and the publication date is not in 2005
Q(question__startswith="Who") | ~Q(pub_date__year=2005)

# Combined example
Poll.objects.get(
Q(question__startswith="Who"),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
)
# Translates to SQL:
# SELECT * FROM polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02'
OR pub_date = '2005-05-06')

from django.db.models import Q

# Query entries that start with "Who" or "What"


Q(question__startswith="Who") | Q(question__startswith="What")
# Equivalent SQL: WHERE question LIKE 'Who%' OR question LIKE 'What%'

# Query entries where question starts with "Who" and the publication date is not in 2005
Q(question__startswith="Who") | ~Q(pub_date__year=2005)

# Combined example
Poll.objects.get(
Q(question__startswith="Who"),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
)
# Translates to SQL:
# SELECT * FROM polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02' OR
pub_date = '2005-05-06')

from datetime import date

start_date = date(2023, 1, 1)
end_date = date(2023, 12, 31)

records = MyModel.objects.filter(date_field__range=(start_date, end_date))

Using __gte and __lte Lookups

from datetime import date

start_date = date(2023, 1, 1)
end_date = date(2023, 12, 31)

records = MyModel.objects.filter(date_field__gte=start_date, date_field__lte=end_date)

Both methods will retrieve records where the date_field falls within the specified date range.

Here is an explanation of the Admin configuration for the Django admin panel:

Django Admin Configuration

from django.contrib import admin


from .models import product, UserDetails, Address, Author, Books, Person, City, Blog,
Entry

# Custom admin class for Address model


class AddressAdmin(admin.ModelAdmin):
# Method to display user's email in the admin panel
def userEmail(self, obj):
return obj.user_id.email

# Display fields in the list view of the admin panel


list_display = ('city', 'state', 'user_id', 'userEmail')
# Filters for list view
list_filter = ("city", "state")

# Fields to search by in the admin panel


search_fields = ("city",)

# Ordering of the list view


ordering = ("state", "city")

# Allow sorting by user's email


userEmail.admin_order_field = "user_id__email"

# Register models with the admin panel


admin.site.register(product)
admin.site.register(UserDetails)
admin.site.register(Address, AddressAdmin) # Using custom AddressAdmin class
admin.site.register(Author)
admin.site.register(Books)
admin.site.register(Person)
admin.site.register(City)
admin.site.register(Blog)
admin.site.register(Entry)

Key Points:

1. Custom Admin Class (AddressAdmin):


○ userEmail Method: This method retrieves and displays the email associated
with the user_id foreign key. It allows the admin panel to show a more
user-friendly email field instead of just displaying the user_id.
○ list_display: Specifies which fields will be shown in the list view of the
Address model. The userEmail method is included here, allowing the email to
be displayed.
○ list_filter: Adds filtering options in the admin panel based on the city and
state fields, enabling easy filtering of entries by these attributes.
○ search_fields: Provides a search box to search entries by the city field.
○ ordering: Sets the default ordering of entries in the list view by state and
city.
○ userEmail.admin_order_field: Enables sorting by the userEmail method
in the list view, which is useful for sorting entries by the associated user's email.
2. Model Registration:
○ All the models (product, UserDetails, Address, Author, Books, Person,
City, Blog, Entry) are registered with the admin site.
○ The Address model is registered with the custom AddressAdmin class to apply
the specific configurations made in that class.

This configuration ensures that the Address model is displayed in the admin panel with
enhanced usability, including custom email display, filtering, search, and ordering options.

Here are some advanced configurations and customizations you can explore to enhance the
Django admin panel:

1. Custom Actions

● You can define custom actions that can be applied to the selected records in the admin
panel.

from django.contrib import admin


from .models import Product

def mark_as_featured(modeladmin, request, queryset):


queryset.update(is_featured=True)
mark_as_featured.short_description = "Mark selected products as featured"

class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'price', 'is_featured')
actions = [mark_as_featured]

admin.site.register(Product, ProductAdmin)

2. Inlines

● Inlines allow you to include related models within the admin interface of another model

from django.contrib import admin


from .models import Author, Book

class BookInline(admin.TabularInline):
model = Book
extra = 1

class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline]

admin.site.register(Author, AuthorAdmin)

3. Custom Forms

● You can customize the forms used in the admin panel by using custom form classes

from django import forms


from django.contrib import admin
from .models import Product

class ProductAdminForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name', 'price', 'description']

def clean_price(self):
price = self.cleaned_data.get('price')
if price < 0:
raise forms.ValidationError("Price cannot be negative")
return price

class ProductAdmin(admin.ModelAdmin):
form = ProductAdminForm

admin.site.register(Product, ProductAdmin)

4. Overriding Default Templates

● Django admin uses templates that can be overridden to customize the look and feel.

Create a templates/admin/ directory and override templates such as change_list.html,


change_form.html, etc.

<!-- templates/admin/change_list.html -->


{% extends "admin/change_list.html" %}
{% block content %}
<h1>Custom Admin List View</h1>
{{ block.super }}
{% endblock %}

5. Custom Admin URLs

● Add custom views or actions to your admin interface.

from django.urls import path


from django.http import HttpResponse
from django.contrib import admin

class MyAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path('my_custom_view/', self.my_custom_view),
]
return custom_urls + urls

def my_custom_view(self, request):


return HttpResponse("This is a custom view")

admin.site.register(Product, MyAdmin)

6. Admin Panel Security

● Enhance security by restricting admin access based on user groups or permissions

from django.contrib import admin


from django.contrib.auth.models import User

class SecureAdminSite(admin.AdminSite):
def has_permission(self, request):
return request.user.is_active and request.user.is_staff and
request.user.groups.filter(name='AdminGroup').exists()

admin_site = SecureAdminSite(name='secure_admin')
admin_site.register(User)

7. Custom Filters

● Create custom filters for specific use cases

from django.contrib import admin


from .models import Product

class PriceFilter(admin.SimpleListFilter):
title = 'price'
parameter_name = 'price'

def lookups(self, request, model_admin):


return (
('<50', 'Less than $50'),
('50-100', '$50-$100'),
('>100', 'More than $100'),
)

def queryset(self, request, queryset):


if self.value() == '<50':
return queryset.filter(price__lt=50)
elif self.value() == '50-100':
return queryset.filter(price__gte=50, price__lte=100)
elif self.value() == '>100':
return queryset.filter(price__gt=100)

class ProductAdmin(admin.ModelAdmin):
list_filter = (PriceFilter,)

admin.site.register(Product, ProductAdmin)

8. Custom Admin Widgets

● Use custom widgets in your admin forms for a better user experience

from django.contrib import admin


from django.forms import TextInput
from django.db import models
from .models import Product

class ProductAdmin(admin.ModelAdmin):
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size': '20'})},
}

admin.site.register(Product, ProductAdmin)

These advanced configurations can significantly improve the usability, functionality, and security
of your Django admin panel.

Adding Filters with list_filter

The list_filter attribute allows you to add filters to the admin list view, making it easier to
search for specific records.

class YourModelAdmin(admin.ModelAdmin):
list_filter = ('field1', 'field2') # Replace with your actual field names

admin.site.register(YourModel, YourModelAdmin)

You can even filter based on related models by using the double underscore (__) syntax:

class BookAdmin(admin.ModelAdmin):
list_filter = ('author__name',) # Filter books by author's name

admin.site.register(Book, BookAdmin)

c. Displaying Foreign Key Fields in List View

If your model has a foreign key, you can display the related model's fields using a custom
method in the list_display attribute.

class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'get_author_name', 'published_date')
def get_author_name(self, obj):
return obj.author.name if obj.author else "N/A"

get_author_name.short_description = 'Author Name'

admin.site.register(Book, BookAdmin)

Grouping Fields with fieldsets

Use fieldsets to organize fields into sections in the admin form, making it more user-friendly.

class YourModelAdmin(admin.ModelAdmin):
fieldsets = (
('Basic Information', {
'fields': ('field1', 'field2'),
'description': 'This section contains basic fields.',
}),
('Advanced Options', {
'fields': ('field3', 'field4'),
'classes': ('collapse',), # Make this section collapsible
}),
)

admin.site.register(YourModel, YourModelAdmin)

Example with a Complete Model

Let's consider a model Product and demonstrate how to register and customize it in the
Django admin.

Model Definition:

from django.db import models

class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.IntegerField()
category = models.ForeignKey('Category', on_delete=models.CASCADE)

def __str__(self):
return self.name

Admin Customization:

from django.contrib import admin


from .models import Product

class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'price', 'quantity', 'get_category_name')
list_filter = ('category__name',)

def get_category_name(self, obj):


return obj.category.name if obj.category else "N/A"

get_category_name.short_description = 'Category'

admin.site.register(Product, ProductAdmin)

Summary

● Basic Registration: Use admin.site.register() to register your models with the


admin site.
● Custom Display: Utilize list_display to control which fields are shown in the list
view.
● Filtering: Implement list_filter to add filtering options based on model fields.
● Foreign Key Handling: Display fields from related models using custom methods in
list_display.
● Form Organization: Use fieldsets to group fields into sections, improving the form's
layout.

These techniques allow you to create a more intuitive and powerful admin interface, enhancing
the user experience for managing your Django models.

Django Model Methods and Properties


Django's models offer powerful tools to encapsulate business logic, perform custom operations,
and define computed fields. By utilizing model methods, properties, and special magic methods,
you can enhance the functionality of your Django models in a structured way.

Model Methods and Properties

1. Defining Methods in Models:

● Custom Methods: These are defined within the model to encapsulate logic related to
that model. They typically operate on individual model instances.
Example:

class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
age = models.IntegerField()

def age_status(self):
if self.age < 18:
return "under age"
return "adult"

Usage:

person = Person.objects.get(id=1)
print(person.age_status()) # Outputs: "adult" or "under age"

Computed Fields (Using @property): Properties allow for on-the-fly calculation of values
based on model fields. They do not save the result in the database but compute it when
accessed.

Example:

class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)

@property
def full_name(self):
return f"{self.first_name} {self.last_name}"

Usage:

person = Person.objects.get(id=1)
print(person.full_name) # Outputs: "John Doe"

2. Overriding the save() Method: The save() method is executed when a model instance is
saved to the database. You can override it to add custom logic before or after saving.

Example:

from django.utils.text import slugify

class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()

def save(self, *args, **kwargs):


self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)

Usage:

post = Post.objects.create(title="My First Post")


print(post.slug) # Outputs: "my-first-post"

3. The Meta Class: The Meta class in a model allows you to define various metadata options
for your model, including table names, ordering, constraints, and more.

Common Meta Options:

● db_table: Custom table name.


● ordering: Default ordering for query sets.
● verbose_name: Human-readable name in the admin.
● unique_together: Composite unique constraint.
● indexes: Custom database indexes.
● constraints: Custom database constraints.
● permissions: Custom permissions for the model.
● abstract: Declares the model as abstract, meaning it won’t be used to create any
database table.

1. db_table: Custom Table Name

By default, Django creates a database table name by combining the app name and the model
name. You can override this default behavior by specifying a custom table name using
db_table.

Example:

class Product(models.Model):

name = models.CharField(max_length=255)

price = models.DecimalField(max_digits=10, decimal_places=2)

class Meta:

db_table = 'custom_product_table'

In this example, the Product model will use the table name custom_product_table instead
of the default appname_product.

2. ordering: Default Ordering for Querysets

You can specify the default ordering of querysets when retrieving objects from the database.

Example:

class Product(models.Model):

name = models.CharField(max_length=255)

price = models.DecimalField(max_digits=10, decimal_places=2)


class Meta:

ordering = ['price', 'name']

In this example, products will be ordered by price in ascending order, and if two products have
the same price, they will be ordered by name.

3. verbose_name: Human-Readable Name in the Admin

verbose_name allows you to specify a human-readable name for the model, which is used in
the Django admin interface.

Example:

class Product(models.Model):

name = models.CharField(max_length=255)

class Meta:

verbose_name = 'Item'

In the admin interface, the Product model will be referred to as Item.

4. unique_together: Composite Unique Constraint

unique_together ensures that a combination of fields must be unique across the entire table.

Example:

class Order(models.Model):

product = models.ForeignKey(Product, on_delete=models.CASCADE)

customer = models.ForeignKey(Customer, on_delete=models.CASCADE)


class Meta:

unique_together = ['product', 'customer']

In this example, a customer cannot have the same product in their order list more than once.

5. indexes: Custom Database Indexes

You can create custom indexes on fields or expressions to optimize query performance.

Example:

class Product(models.Model):

name = models.CharField(max_length=255)

price = models.DecimalField(max_digits=10, decimal_places=2)

class Meta:

indexes = [

models.Index(fields=['price']),

models.Index(fields=['name', 'price']),

In this example, indexes are created on the price field and on the combination of name and
price fields to speed up lookups.

6. constraints: Custom Database Constraints

You can enforce custom constraints at the database level.

Example:

from django.db.models import Q


class Product(models.Model):

name = models.CharField(max_length=255)

price = models.DecimalField(max_digits=10, decimal_places=2)

discount_price = models.DecimalField(max_digits=10, decimal_places=2)

class Meta:

constraints = [

models.CheckConstraint(check=Q(price__gte=0), name='price_positive'),

models.CheckConstraint(check=Q(discount_price__lte=F('price')),
name='valid_discount_price'),

In this example, the constraints ensure that the price is non-negative and that the
discount_price is not greater than the price.

7. permissions: Custom Permissions for the Model

You can define custom permissions that can be assigned to users or groups.

Example:

class Product(models.Model):

name = models.CharField(max_length=255)

class Meta:

permissions = [

('can_view_product', 'Can view product'),


('can_edit_product', 'Can edit product'),

In this example, two custom permissions can_view_product and can_edit_product are


created for the Product model.

8. abstract: Declaring an Abstract Model

An abstract model is a model that is not created in the database but can be inherited by other
models.

Example:

class TimestampedModel(models.Model):

created_at = models.DateTimeField(auto_now_add=True)

updated_at = models.DateTimeField(auto_now=True)

class Meta:

abstract = True

class Product(TimestampedModel):

name = models.CharField(max_length=255)

class Order(TimestampedModel):

product = models.ForeignKey(Product, on_delete=models.CASCADE)

In this example, TimestampedModel is an abstract model that provides created_at and


updated_at fields to any model that inherits from it. The Product and Order models will
have these fields, but TimestampedModel itself does not create a database table.
Using Python Magic Methods in Django Models

Django models can utilize Python's special magic methods to customize behaviors like
representation, initialization, comparison, and more.

1. __str__: Defines the string representation of a model instance.

Example:

class Author(models.Model):

name = models.CharField(max_length=100)

def __str__(self):

return self.name

2. __repr__: Provides an unambiguous string representation, often used for debugging.

Example:

class Author(models.Model):

name = models.CharField(max_length=100)

def __repr__(self):

return f"<Author: {self.name}>"


3. save: Customizes behavior when saving an instance.

Example:

class MyModel(models.Model):

name = models.CharField(max_length=100)

def save(self, *args, **kwargs):

# Custom logic

super().save(*args, **kwargs)

4. delete: Customizes behavior when deleting an instance.

Example:

class MyModel(models.Model):

name = models.CharField(max_length=100)

def delete(self, *args, **kwargs):

# Custom logic

super().delete(*args, **kwargs)

5. __eq__ and __ne__: Define custom equality and inequality operations.

Example:

class MyModel(models.Model):
name = models.CharField(max_length=100)

def __eq__(self, other):

return self.name == other.name

def __ne__(self, other):

return self.name != other.name

SECTION-3: STATIC FILES AND FORMS

3.1: FORMS

Step 1: Create the Model First, define the model for which you will fetch data. In this example,
we'll create an Employee model to store basic employee details.

# models.py

from django.db import models

class Employee(models.Model):

name = models.CharField(max_length=90)

email = models.EmailField()

phone = models.IntegerField()

address = models.TextField()

Step 2: Create the Forms Django provides two ways to create forms: manually using
forms.Form or automatically using forms.ModelForm. Here’s how to create both types:

# forms.py
from django import forms

from .models import Employee

class YourForm(forms.Form):

# Define form fields manually

name = forms.CharField(max_length=100)

email = forms.EmailField()

phone = forms.IntegerField()

class YourModelForm(forms.ModelForm):

class Meta:

model = Employee

fields = ['name', 'email', 'phone'] # Specify the fields to include in the form

Explanation:

● YourForm: This form is created manually by defining each field individually.


● YourModelForm: This form is created based on the Employee model. It automatically
includes the specified fields (name, email, and phone).

Step 3: Write the Views Views are responsible for handling user input and rendering the
appropriate HTML template. Here, we create views to render our forms and handle form
submissions.

# views.py

from django.shortcuts import render, redirect

from .forms import YourForm, YourModelForm


def your_view(request):

form = YourForm()

return render(request, 'your_template.html', {'form': form})

def your_view_url_name(request):

if request.method == 'POST':

form = YourModelForm(request.POST)

if form.is_valid():

# Process the form data

name = form.cleaned_data['name']

email = form.cleaned_data['email']

print(name, email) # Example of processing form data

form.save() # Save the data to the database

return render(request, "normalform.html")

Explanation:

● your_view: Renders a simple form using YourForm.


● your_view_url_name: Handles form submission using YourModelForm. If the form is
valid, it processes and saves the data.

Step 4: Create the Templates The HTML template is where the form will be displayed. Below is
an example of how to create a template for displaying YourForm.

<!-- your_template.html -->

<!DOCTYPE html>

<html lang="en">

<head>
<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Your Form Example</title>

</head>

<body>

<h1>Your Form</h1>

<form method="post" action="{% url 'your_view_url_name' %}">

{% csrf_token %}

{{ form.non_field_errors }}

<div class="form-group">

{{ form.name }}

{{ form.name.errors }}

</div>

<div class="form-group">

{{ form.email }}

{{ form.email.errors }}

</div>

<div class="form-group">

{{ form.phone }}
{{ form.phone.errors }}

</div>

<input type="submit" value="Submit">

</form>

</body>

</html>

Explanation:

● The template uses Django template tags to render form fields and handle errors.
● The form’s action attribute points to the URL where the form will be submitted.

Step 5: Configure URLs Finally, set up the URL configurations for your views so that they can
be accessed via specific endpoints.

# project-level urls.py

from django.contrib import admin

from django.urls import path, include

urlpatterns = [

path("admin/", admin.site.urls),

path("app1/", include("app1.urls")),

# app-level urls.py
from django.urls import path

from .views import your_view, your_view_url_name

urlpatterns = [

path("your_view", your_view, name="your_view"),

path("your_view_url_name", your_view_url_name, name="your_view_url_name"),

Explanation:

● Project-level urls.py: Includes the URLs defined in the app.


● App-level urls.py: Maps specific views to URL paths.

Step 6: Display Data in a Template If you want to display the details of all employees stored in
the database, create a new view and template.

# views.py

from .models import Employee

def user_detail(request):

user_dict = Employee.objects.all()

return render(request, "user_detail.html", {"users": user_dict})

<!-- user_detail.html -->

<!DOCTYPE html>

<html lang="en">
<head>

<meta charset="UTF-8">

<title>User Details</title>

</head>

<body>

<h1>The user details list are:</h1>

<ol>

{% for user in users %}

<li>{{ user.name }} - {{ user.email }}</li>

{% endfor %}

</ol>

</body>

</html>

Explanation:

● user_detail: This view fetches all employee records and passes them to the
user_detail.html template.
● user_detail.html: The template iterates over the users context variable and displays
each user's name and email in an ordered list.

This completes the basic setup for handling forms in Django, displaying form data, and
rendering it in a template.

Auto-Detect HTML in Generic Views


Django’s generic views are a powerful way to create views without having to write repetitive
code. Here’s how you can set up your project to auto-detect HTML templates when using
generic views, and how to extend the functionality with additional context data.

Step 1: Create Your Necessary Models

First, you need to define the models you will be working with. Here, we have three models:
Publisher, Author, and Book.

# models.py

from django.db import models

class Publisher(models.Model):

name = models.CharField(max_length=30)

address = models.CharField(max_length=50)

city = models.CharField(max_length=60)

state_province = models.CharField(max_length=30)

country = models.CharField(max_length=50)

website = models.URLField()

class Meta:

ordering = ["-name"]

def __str__(self):

return self.name

class Author(models.Model):

salutation = models.CharField(max_length=10)
name = models.CharField(max_length=200)

email = models.EmailField()

headshot = models.ImageField(upload_to="author_headshots")

def __str__(self):

return self.name

class Book(models.Model):

title = models.CharField(max_length=100)

authors = models.ManyToManyField(Author)

publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)

publication_date = models.DateField()

Step 2: Create Templates

Create a folder named templates in your project’s root directory, if it doesn’t already exist.
Inside the templates folder, create another folder with the same name as your app (e.g.,
app1). This is where you’ll place your HTML templates.

For a ListView, create a template named publisher_list.html:

<!-- templates/app1/publisher_list.html -->

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Publishers</title>
</head>

<body>

<h2>Publishers</h2>

<ul>

{% for publisher in object_list %}

<li>{{ publisher.name }}</li>

{% endfor %}

</ul>

</body>

</html>

Step 3: Configure the Views

Create a ListView for the Publisher model. This view will automatically detect the
publisher_list.html template you created earlier.

# views.py

from django.views.generic import ListView

from .models import Publisher

class PublisherListView(ListView):

model = Publisher

This generic view will look for a template named publisher_list.html in the app1 directory
by default.
Step 4: Set Up URLs

Configure the URL patterns to connect your views with specific URLs

# app1/urls.py

from django.urls import path

from .views import PublisherListView

urlpatterns = [

path("publish", PublisherListView.as_view(), name="publisher_list"),

In your project-level urls.py, include the app1 URLs.

# project-level urls.py

from django.contrib import admin

from django.urls import path, include

urlpatterns = [

path("admin/", admin.site.urls),

path("app1/", include("app1.urls")),

Running the Server


After completing these steps, running the Django development server will allow you to visit
/app1/publish and see the list of publishers rendered by the publisher_list.html
template.

Generic Detail View

When you need to present additional information, such as a list of books associated with each
publisher, you can extend the DetailView to include extra context data.

Step 1: Extend the DetailView

Create a DetailView for the Publisher model and override the get_context_data
method to add a list of books to the context.

# views.py

from django.views.generic import DetailView

from .models import Publisher, Book

class PublisherDetailView(DetailView):

model = Publisher

def get_context_data(self, **kwargs):

context = super().get_context_data(**kwargs)

# Add a list of all books published by this publisher

context["book_list"] = Book.objects.filter(publisher=self.object)

return context

Step 2: Create the Template

Create a template named publisher_detail.html to display the publisher’s details along


with the list of books.
<!-- templates/app1/publisher_detail.html -->

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Publisher Detail</title>

</head>

<body>

<h2>{{ object.name }}</h2>

<p>{{ object.address }}, {{ object.city }}, {{ object.country }}</p>

<p>Website: <a href="{{ object.website }}">{{ object.website }}</a></p>

<h3>Books Published by {{ object.name }}</h3>

<ul>

{% for book in book_list %}

<li>{{ book.title }} by {{ book.authors.all|join:", " }}</li>

{% endfor %}

</ul>

</body>

</html>
Step 3: Update URLs

Add a new URL pattern to map to the PublisherDetailView.

# app1/urls.py

from django.urls import path

from .views import PublisherListView, PublisherDetailView

urlpatterns = [

path("publish", PublisherListView.as_view(), name="publisher_list"),

path("pub_detail/<int:pk>", PublisherDetailView.as_view(), name="publisher_detail"),

Conclusion

By following these steps, you have set up a Django project that auto-detects HTML templates
using generic views and extends the functionality of generic views to include additional context
data. This allows for a clean and efficient way to manage and display data within your Django
application.

Connecting CSS with HTML in Django

To include CSS in your Django templates, follow these steps:

Step 1: Create the Static Folder

First, create a static folder within your Django app. Inside the static folder, create a css
folder and place your CSS files inside it.

Directory Structure:

your_project/

├── your_app/
│ ├── static/

│ │ ├── css/

│ │ │ └── styles.css

│ │ ├── js/

│ │ └── images/

├── manage.py

└── your_project/

In this structure, styles.css is located in the static/css/ directory.

Step 2: Create the HTML File and Connect It to the CSS File

Create an HTML file in your templates directory that links to the CSS file using the {%
static %} template tag.

Example HTML File:

<!-- your_app/templates/css_connector.html -->

{% load static %}

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Your HTML Template</title>


<!-- Connect your static CSS file -->

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

</head>

<body>

<!-- Your HTML content goes here -->

<div class="main-content">

<h1>Hello, Django!</h1>

<p>This is a simple example.</p>

<a href="#">Click me</a>

<hr>

</div>

</body>

</html>

Example CSS File:

/* static/css/styles.css */

/* Reset some default margin and padding */

body, h1, p {

margin: 0;

padding: 0;

/* Apply a background color to the body */


body {

background-color: #f4f4f4;

font-family: 'Arial', sans-serif;

/* Style the header */

h1 {

color: #333;

background-color: #fff;

padding: 20px;

text-align: center;

/* Style the main content area */

.main-content {

max-width: 800px;

margin: 20px auto;

background-color: #fff;

padding: 20px;

/* Style links */

a{

color: #007bff;
text-decoration: none;

a:hover {

text-decoration: underline;

/* Add some spacing between elements */

hr {

margin: 20px 0;

Step 3: Create the View

In your views.py, create a view to render the css_connector.html template.

Example View:

# views.py

from django.shortcuts import render

def css_view(request):

return render(request, "css_connector.html")

Step 4: Connect the URLs

Add the necessary URL configuration to connect your view.

App-Level urls.py:
# urls.py

from django.urls import path

from .views import css_view

urlpatterns = [

path("css-example/", css_view, name="css_view"),

Project-Level urls.py:

Ensure that your project-level urls.py includes the app’s URLs.

# project-level urls.py

from django.contrib import admin

from django.urls import path, include

urlpatterns = [

path("admin/", admin.site.urls),

path("app1/", include("app1.urls")), # Adjust app1 to your app name

Step 5: Run the Server

Now, run your Django development server using the command:

Visit http://127.0.0.1:8000/app1/css-example/ in your browser to see your HTML


page styled with the CSS you linked.
Additional Information on Viewing Subsets of Objects

When using Django's generic views, such as ListView, you often work with a subset of objects
from your database. While the model argument specifies which model to query, you can further
refine this using the queryset argument.

Example with queryset:

# views.py

from django.views.generic import ListView

from .models import Book

class BookListView(ListView):

model = Book

queryset = Book.objects.filter(publication_date__year=2024) # Example: filter books


by year

Generic Views in Django

Django's generic views are powerful tools that simplify the development of common web
patterns by providing reusable views that handle common tasks like displaying lists of objects,
showing detail views, handling forms, and more. Below are some of the most commonly used
generic views in Django.

1. ListView

● Purpose: To display a list of objects from a model.


● Usage: It renders a template and passes a queryset of objects to the template for
rendering.

from django.views.generic import ListView

from .models import YourModel


class YourModelListView(ListView):

model = YourModel

template_name = 'your_app/your_model_list.html'

context_object_name = 'object_list' # Name of the variable to use in the template

Example with a custom queryset:

class PersonDetails(ListView):

template_name = "person.html"

context_object_name = 'data'

def get_queryset(self):

data = Person.objects.all().first()

print(data.name)

return data

2. DetailView

● Purpose: To display the details of a single object from a model.

from django.views.generic import DetailView

from .models import YourModel

class YourModelDetailView(DetailView):

model = YourModel

template_name = 'your_app/your_model_detail.html'
context_object_name = 'object' # Name of the variable to use in the template

3. CreateView

● Purpose: To display a form for creating a new object and handle form submissions.

from django.views.generic import CreateView

from .models import YourModel

class YourModelCreateView(CreateView):

model = YourModel

template_name = 'your_app/your_model_form.html'

fields = ['field1', 'field2'] # Fields to display in the form

4. UpdateView

● Purpose: Similar to CreateView, but used for updating existing objects.

from django.views.generic import UpdateView

from .models import YourModel

class YourModelUpdateView(UpdateView):

model = YourModel

template_name = 'your_app/your_model_form.html'

fields = ['field1', 'field2'] # Fields to display in the form


5. DeleteView

● Purpose: To delete an object from the database

from django.views.generic import DeleteView

from .models import YourModel

class YourModelDeleteView(DeleteView):

model = YourModel

template_name = 'your_app/your_model_confirm_delete.html'

success_url = '/success_url/' # URL to redirect after successful deletion

Django Rest Framework (DRF) API Views

Django Rest Framework provides powerful tools for building REST APIs in Django. The
api_view decorator is central to this, allowing you to define which HTTP methods your view
should respond to.

1. Simple API View Example

from django.shortcuts import render

from rest_framework.decorators import api_view

from rest_framework.response import Response

from .models import Student

@api_view(['GET', 'POST', 'PUT'])

def student_view(request):

if request.method == 'GET':
data = Student.objects.all().values()

return Response({'status': True, 'student_data': data})

if request.method == 'POST':

data = request.data

Student.objects.create(

name=data['name'],

student_id=data['student_id'],

grade_desc=data['grade_desc']

return Response({'status': 'in progress'})

2. Using API Policy Decorators

Django Rest Framework provides decorators like @throttle_classes to apply custom


throttling, authentication, or permission policies.

Throttle Example:

from rest_framework.decorators import api_view, throttle_classes

from rest_framework.throttling import UserRateThrottle

class OncePerDayUserThrottle(UserRateThrottle):

rate = '1/day'

@api_view(['GET'])

@throttle_classes([OncePerDayUserThrottle])

def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})

Summary

● Generic Views: Django's generic views (ListView, DetailView, CreateView,


UpdateView, DeleteView) provide a high-level way to handle common web patterns
without writing redundant code.
● DRF API Views: Django Rest Framework's api_view decorator, along with additional
decorators like @throttle_classes, makes it easy to build robust and secure REST
APIs.

These tools help streamline the development process and allow you to focus on the specific
business logic and customizations needed for your application.

Getting Data from an HTML Form in Django

In Django, handling data sent from an HTML form is straightforward. You can use Django's
HttpRequest object to access the data submitted through the form. Below is a step-by-step
guide to achieve this.

1. Create the HTML Form

First, create an HTML form within your template, myform.html, located in the templates
directory.

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>My Form</title>

</head>

<body>

<form method="post" action="{% url 'process_form' %}">


{% csrf_token %}

<label for="username">Username:</label>

<input type="text" id="username" name="username" required>

<br>

<label for="password">Password:</label>

<input type="password" id="password" name="password" required>

<br>

<input type="submit" value="Submit">

</form>

</body>

</html>

2. Create the Views

Next, create the views in your views.py file to handle the form display and processing.

from django.shortcuts import render

from django.http import HttpResponse

# View to render the form

def my_form(request):

return render(request, 'myform.html')

# View to process the form submission

def process_form(request):

if request.method == 'POST':
# Get data from the form

username = request.POST.get('username')

password = request.POST.get('password')

# Do something with the data (e.g., save to the database)

print(f'Username: {username}, Password: {password}')

return HttpResponse('Form submitted successfully!')

else:

return HttpResponse('Invalid request method')

3. Set Up URL Patterns

In your app's urls.py file, define the URL patterns to map the form view and the processing
view.

from django.urls import path

from .views import my_form, process_form

urlpatterns = [

path('myform/', my_form, name='my_form'),

path('process_form/', process_form, name='process_form'),

]
Make sure these URLs are included in your main urls.py file if you're working within a larger
project.

4. Run the Server and Test

Run your Django development server using:

python manage.py runserver

Visit http://127.0.0.1:8000/myform/ to see your form in action. After submitting the


form, you should see the form data printed in the console, and a success message displayed on
the web page.

Summary

● Form Handling: Django uses the HttpRequest object to access data sent from forms
using the POST method.
● CSRF Protection: The {% csrf_token %} template tag is crucial for protecting
against CSRF attacks.
● Form Processing: The process_form view checks the request method to ensure it's
processing a POST request, retrieves the data using request.POST.get(), and then
handles it as needed.

This basic example forms the foundation for handling more complex forms in Django. For more
advanced form processing, consider using Django's forms module, which provides built-in
validation, error handling, and more structured form management.

This detailed section on creating a superuser and overriding the AbstractUser model in
Django, as well as setting up a user API for CRUD operations, covers some advanced aspects
of Django user management. Here's a summary and enhancement of the steps provided:

Creating a Superuser:

1. Navigate to Project Directory: Open a terminal and navigate to your Django project's
root directory (where manage.py is located).
2. Run Command to Create Superuser: Execute the following command:
python manage.py createsuperuser

Enter Superuser Details: You'll be prompted to enter a username, email, and password. These
credentials will be used to access the Django admin panel.

Access Admin Panel: Start the development server with python manage.py runserver
and log in at http://localhost:8000/admin/ using the superuser credentials.

Overriding the AbstractUser Model:

If you need more control over the user model, such as using an email instead of a username for
authentication or adding custom fields, follow these steps:

1. Create Custom User Model:


○ Create a custom user model by subclassing AbstractUser and override the
username field to use email instead.
○ Define a custom manager (CustomUserManager) to handle user and superuser
creation.

from django.contrib.auth.models import AbstractUser, BaseUserManager

from django.db import models

class CustomUserManager(BaseUserManager):

def create_user(self, email, password=None, **extra_fields):

if not email:

raise ValueError('The Email field must be set')

email = self.normalize_email(email)

user = self.model(email=email, **extra_fields)

user.set_password(password)

user.save(using=self._db)

return user
def create_superuser(self, email, password=None, **extra_fields):

extra_fields.setdefault('is_staff', True)

extra_fields.setdefault('is_superuser', True)

if extra_fields.get('is_staff') is not True:

raise ValueError('Superuser must have is_staff=True.')

if extra_fields.get('is_superuser') is not True:

raise ValueError('Superuser must have is_superuser=True.')

return self.create_user(email, password, **extra_fields)

class CustomUser(AbstractUser):

email = models.EmailField(unique=True)

username = None

USERNAME_FIELD = 'email'

REQUIRED_FIELDS = []

objects = CustomUserManager()

def __str__(self):

return self.email

Update settings.py:
● Point Django to use your custom user model by setting AUTH_USER_MODEL in
settings.py:

AUTH_USER_MODEL = 'your_app.CustomUser'

Make Migrations and Migrate:

● Run the following commands to create and apply the necessary database migrations:

python manage.py makemigrations

python manage.py migrate

Creating a User API (CRUD Operations):

To handle user creation through an API, you can use Django REST Framework (DRF):

1. Create a Serializer (serializers.py):


○ Define how your custom user model data will be converted to and from JSON:

from rest_framework.serializers import ModelSerializer

from .models import CustomUser

class UserSerializer(ModelSerializer):

class Meta:

model = CustomUser

fields = ('email', 'password')

def create(self, validated_data):


user = CustomUser(

email=validated_data["email"],

password=validated_data["password"]

user.set_password(validated_data["password"])

user.save()

return user

Create Views (views.py):

● Handle HTTP requests (e.g., POST for creating users) and use the serializer for data
validation and saving:

from rest_framework.decorators import api_view

from rest_framework.response import Response

from rest_framework import status

from .serializers import UserSerializer

@api_view(["POST"])

def user_create(request):

if request.method == "POST":

serializer = UserSerializer(data=request.data)

if serializer.is_valid():

user = serializer.save()

return Response({"email": user.email}, status=status.HTTP_201_CREATED)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


This setup allows you to create users through an API endpoint while leveraging Django's
powerful authentication system. Remember, if you're planning to override the AbstractUser
model, it's critical to do this at the start of your project, as retrofitting it into an existing project
can lead to complications.

Token Authentication with Django REST


Framework (DRF)
Token-based authentication is a popular method for securing APIs, where each user is given a
token that must be included in every API request to prove their identity.

Step 1: Set Up Token Creation on User Registration

When a new user is created, we need to generate a token for that user. We can do this by using
Django signals.

1. Import necessary modules:

from django.db.models.signals import post_save

from django.dispatch import receiver

from rest_framework.authtoken.models import Token

from .models import CustomUser

Create a signal to generate a token after a user is created:

@receiver(post_save, sender=CustomUser)

def create_auth_token(sender, instance=None, created=False, **kwargs):

if created:

Token.objects.create(user=instance)
Explanation:

● The post_save signal is triggered after a user instance is saved.


● The create_auth_token function checks if a new user was created
(created=True). If so, it generates a token for that user.

Step 2: Create a Serializer for the Custom User Model

Serializers are used to convert complex data types like Django models into JSON and vice
versa.

1. Create a serializer for the CustomUser model:

from rest_framework.serializers import ModelSerializer

from .models import CustomUser

class UserSerializer(ModelSerializer):

class Meta:

model = CustomUser

fields = ('email', 'password')

def create(self, validated_data):

user = CustomUser(

email=validated_data['email'],

user.set_password(validated_data['password'])

user.save()

return user
Explanation:

● The UserSerializer includes email and password fields for the CustomUser
model.
● The create method ensures the password is hashed before saving the user.

Step 3: Create Views for User Registration and Login

1. Create a user registration view:

from rest_framework.decorators import api_view

from rest_framework.response import Response

from rest_framework import status

from .serializers import UserSerializer

@api_view(["POST"])

def user_create(request):

if request.method == "POST":

serializer = UserSerializer(data=request.data)

if serializer.is_valid():

user = serializer.save()

return Response({"email": user.email}, status=status.HTTP_201_CREATED)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Explanation:
● This view allows clients to register a new user by sending a POST request with email
and password.
● Upon successful registration, the user's email is returned.

Create a login view to authenticate users and return their token:

from rest_framework.authtoken.models import Token

from django.contrib.auth import authenticate, login

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt

@api_view(["POST"])

def login_view(request):

if request.method == 'POST':

data = request.data

user = authenticate(request, email=data['email'], password=data['password'])

if user is not None:

login(request, user)

token = Token.objects.get(user=user)

return Response({"token": token.key}, status=status.HTTP_200_OK)

else:

return Response({"error": "Invalid credentials"},


status=status.HTTP_401_UNAUTHORIZED)

1. Explanation:
○ This view authenticates the user with their email and password.
○ If successful, it retrieves and returns the user’s token.
Step 4: Configure Django Settings

1. Add necessary apps to INSTALLED_APPS in settings.py:

INSTALLED_APPS = [

# Other installed apps

'rest_framework',

'rest_framework.authtoken',

Ensure AuthenticationMiddleware is enabled in MIDDLEWARE:

MIDDLEWARE = [

# Other middleware

'django.contrib.auth.middleware.AuthenticationMiddleware',

Specify the authentication classes in settings.py:

REST_FRAMEWORK = {

'DEFAULT_AUTHENTICATION_CLASSES': [

'rest_framework.authentication.TokenAuthentication',

],

1. Explanation:
○ This ensures that DRF uses token-based authentication for any incoming
requests.
Step 5: Create Protected Views

1. Create a simple authenticated view:

from rest_framework.decorators import api_view, authentication_classes,


permission_classes

from rest_framework.permissions import IsAuthenticated

from rest_framework.authentication import TokenAuthentication

from rest_framework.response import Response

@api_view(["GET"])

@authentication_classes([TokenAuthentication])

@permission_classes([IsAuthenticated])

def authenticated_message(request):

return Response({"message": "This is an authenticated message."})

Explanation:

● This view is protected by token authentication. Only authenticated users can access it.

Create a class-based protected view:

from rest_framework.views import APIView

class ProtectedView(APIView):

authentication_classes = [TokenAuthentication]

permission_classes = [IsAuthenticated]
def get(self, request):

return Response({'message': 'You are authenticated!'})

Step 6: Test Token Authentication

1. Login to get a token:


○ Send a POST request to the login endpoint (/login/) with the user’s
credentials.
○ You’ll receive a token in response.
2. Access a protected view:
○ Use the token to access the protected views.
○ In tools like Postman, add the token in the Authorization header:

Key: Authorization

Value: Token <your_token_here>

Example: Extracting and Using the Bearer Token

Sometimes, you may need to manually handle tokens from the request headers.

@api_view(['GET'])

@permission_classes([IsAuthenticated])

def example_view(request):

auth_header = request.headers.get('Authorization')

if auth_header and auth_header.startswith('Bearer '):

bearer_token = auth_header.split(' ')[1]

return Response({'message': 'Bearer token obtained successfully', 'token':


bearer_token})
else:

return Response({'error': 'Invalid or missing Bearer token'}, status=401)

SECTION IV - API & SECURITY


4.1. Overview of API in Django

What is an API?
An API (Application Programming Interface) allows applications to communicate with each
other. In Django, the most common use of the term "API" refers to building web APIs using
Django REST Framework (DRF). DRF is a powerful toolkit for building Web APIs that can
handle data serialization, authentication, permissions, and more.

To create a basic API using DRF, you typically define serializers, views, and URLs:

● Serializers handle the conversion of complex data types, such as Django models, into
JSON.
● Views define how the API responds to various HTTP methods (GET, POST, etc.).
● URLs determine the routes that map to specific views.

4.2. Introduction to REST API in Django

@api_view Decorator: The @api_view decorator allows you to define views that handle
specific HTTP methods (e.g., GET, POST).

Example:

1. Define a Model:

from django.db import models

class Book(models.Model):

title = models.CharField(max_length=100)

author = models.CharField(max_length=100)
Create a Serializer:

from rest_framework import serializers

from .models import Book

class BookSerializer(serializers.ModelSerializer):

class Meta:

model = Book

fields = '__all__'

Define Views:

from rest_framework.decorators import api_view

from rest_framework.response import Response

from .models import Book

from .serializers import BookSerializer

@api_view(['GET'])

def book_list(request):

books = Book.objects.all()

serializer = BookSerializer(books, many=True)

return Response(serializer.data)

@api_view(['GET'])
def book_detail(request, pk):

book = Book.objects.get(pk=pk)

serializer = BookSerializer(book)

return Response(serializer.data)

Configure URLs:

from django.urls import path

from .views import book_list, book_detail

urlpatterns = [

path('books/', book_list, name='book_list'),

path('books/<int:pk>/', book_detail, name='book_detail'),

Include App URLs in Project URLs:

from django.contrib import admin

from django.urls import path, include

urlpatterns = [

path('admin/', admin.site.urls),

path('api/', include('myapi.urls')),
]

Run Migrations and Start the Development Server:

python manage.py makemigrations

python manage.py migrate

python manage.py runserver

Access the API endpoints at:

● http://localhost:8000/api/books/ (to list books)


● http://localhost:8000/api/books/<id>/ (to retrieve a specific book's details)

4.3. Authentication with DRF

Using the @authentication_classes Decorator:

In DRF, the @authentication_classes decorator is used to specify the authentication


methods that should be applied to incoming requests.

Example:

4.3. Authentication with DRF

Using the @authentication_classes Decorator:

In DRF, the @authentication_classes decorator is used to specify the authentication


methods that should be applied to incoming requests.

Example:

from rest_framework.decorators import authentication_classes

from rest_framework.authentication import BasicAuthentication, SessionAuthentication

from rest_framework.views import APIView


from rest_framework.response import Response

@authentication_classes([BasicAuthentication, SessionAuthentication])

class MyAuthenticatedAPIView(APIView):

def get(self, request):

user = request.user

return Response({'message': f'Hello, {user.username}!'})

4.4. API CRUD Operations

Filtering Required Values in an APIView:

from rest_framework.views import APIView

from rest_framework.response import Response

from .models import Product

class DemoAPIView(APIView):

def get(self, request):

product_data = Product.objects.all().values("id", "name", "price", "desc", "rating",


"offer", "org_email", "org_website")

return Response({"status": True, "data": product_data})

def post(self, request):

data = request.data

Product.objects.create(

name=data['name'],
price=data['price'],

desc=data['desc'],

rating=data['rating'],

offer=data['offer'],

org_email=data['org_email'],

org_website=data['org_website']

return Response({"status": "Data posted successfully"})

Updating a Product by ID:

from rest_framework.views import APIView

from rest_framework.response import Response

from .models import Product

class ProductUpdate(APIView):

def put(self, request, id):

product_instance = Product.objects.get(id=id)

data = request.data

product_instance.name = data.get('name', product_instance.name)

product_instance.desc = data.get('desc', product_instance.desc)

product_instance.price = data.get('price', product_instance.price)

product_instance.rating = data.get('rating', product_instance.rating)

product_instance.offer = data.get('offer', product_instance.offer)


product_instance.org_email = data.get('org_email', product_instance.org_email)

product_instance.org_website = data.get('org_website',
product_instance.org_website)

product_instance.save()

return Response({"status": "Data updated successfully"})

4.5. Advanced CRUD Operations with ForeignKey

Handling Multiple Images with a ForeignKey:

In this example, the Product model has multiple images stored in the ProductImage model.

Models:

from django.db import models

class Product(models.Model):

name = models.CharField(max_length=80, null=True)

price = models.IntegerField(null=True)

desc = models.TextField(null=True)

rating = models.FloatField(default=0, null=True)

offer = models.BooleanField(default=False)

org_email = models.EmailField(null=True)

org_website = models.URLField(null=True)

class ProductImage(models.Model):

product_id = models.ForeignKey(Product, on_delete=models.CASCADE)


image = models.FileField(upload_to="product_images")

Serializer:

from rest_framework.serializers import ModelSerializer

from .models import Product, ProductImage

from rest_framework import serializers

class ProductCreateSerializer(ModelSerializer):

prod_images = serializers.SerializerMethodField()

def get_prod_images(self, obj):

image_data = ProductImage.objects.filter(product_id=obj.id).values()

return image_data

class Meta:

model = Product

fields = "__all__"

def create(self, validated_data):

prod_image = self.context.get("view").request.FILES

product_instance = Product.objects.create(**validated_data)

for image in prod_image.getlist('prod_images'):

ProductImage.objects.create(product_id=product_instance, image=image)
return product_instance

def update(self, instance, validated_data):

image_datas = self.context.get("view").request.FILES

image_id = self.context["request"].data.get("prod_images_id")

delete_image_ids = []

if image_id:

extract_ids = image_id.replace("[", '').replace("]", '').replace(" ", '').split(',')

for delete_id in extract_ids:

delete_image_ids.append(int(delete_id))

instance.name = validated_data.get("name", instance.name)

instance.save()

for image in image_datas.getlist('prod_images'):

ProductImage.objects.create(product_id=instance, image=image)

if delete_image_ids:

ProductImage.objects.filter(product_id=instance,
id__in=delete_image_ids).delete()

return instance
ViewSet:

from rest_framework.viewsets import ModelViewSet

from .serializers import ProductCreateSerializer

from .models import Product

class ProdCreateUpdate(ModelViewSet):

serializer_class = ProductCreateSerializer

queryset = Product.objects.all()

URLs:

from rest_framework.routers import DefaultRouter

from .views import ProdCreateUpdate

router = DefaultRouter()

router.register("prodcreate", ProdCreateUpdate)

urlpatterns = [

path('crud/', include(router.urls)),

]
Adding Extra Paths to a ViewSet:

from rest_framework.decorators import action

from rest_framework.viewsets import ModelViewSet

from rest_framework.response import Response

from .models import Product

class ProductView(ModelViewSet):

queryset = Product.objects.all()

@action(detail=True, methods=["GET"], url_path='top-rated')

def top_rated(self, request, *args, **kwargs):

top_rated = Product.objects.filter(rating__gte=3).values()

return Response({"top_rated": top_rated})

Example API Endpoint:


http://localhost:8080/app1/crudproduct/1/top-rated

4.6. HTTP Status Codes (Out of Syllabus)

● 200 OK: The request was successful.


● 201 Created: The request has been fulfilled, and a new resource has been created.
● 204 No Content: The server successfully processed the request, but there is no
additional content to send.
● 400 Bad Request: The request cannot be fulfilled due to bad syntax.
● 401 Unauthorized: The request requires user authentication.
● 403 Forbidden: The server understood the request, but it refuses to authorize it.
● 404 Not Found: The server has not found anything matching the request URI.
● 405 Method Not Allowed: The method specified in the request is not allowed for the
resource.
● 500 Internal Server Error: The server encountered an unexpected condition which
prevented it from fulfilling the request.
● 503 Service Unavailable: The server is currently unable to handle the request due to
temporary overloading or maintenance.

4.4. Creating a Login and Signup Page in Django


In this section, we'll create login and signup pages using Django's built-in authentication system.
We'll also cover the steps to set up a basic Django project and app, create forms, views, and
templates for user registration and login.

Create a Django App

Navigate to your project directory and create a new Django app named app1:

cd signup

python manage.py startapp app1

Update Settings

In your project's settings.py, add the newly created app to the INSTALLED_APPS list and
configure the authentication backend:

# signup/settings.py

INSTALLED_APPS = [

# ... other apps ...

'app1',

]
# Authentication

AUTHENTICATION_BACKENDS = [

'django.contrib.auth.backends.ModelBackend',

# Configure the templates folder

TEMPLATES = [

"BACKEND": "django.template.backends.django.DjangoTemplates",

"DIRS": ['templates'], # Path to your templates folder

"APP_DIRS": True,

"OPTIONS": {

"context_processors": [

"django.template.context_processors.debug",

"django.template.context_processors.request",

"django.contrib.auth.context_processors.auth",

"django.contrib.messages.context_processors.messages",

],

},

},

]
Create Models

In your app's models.py, create a custom user model if you want to add additional fields
(optional):

# app1/models.py

from django.contrib.auth.models import AbstractUser

from django.db import models

class CustomUser(AbstractUser):

# Add any additional fields you want

pass

Step 6: Update Settings for Custom User Model

Update your project's settings.py to use the custom user model:

# signup/settings.py

AUTH_USER_MODEL = 'app1.CustomUser'

Step 7: Create Forms

Create forms for user registration and login in your app's forms.py:

# app1/forms.py

from django import forms

from django.contrib.auth.forms import UserCreationForm, AuthenticationForm


from .models import CustomUser

class SignUpForm(UserCreationForm):

class Meta:

model = CustomUser

fields = ['username', 'password1', 'password2']

class LoginForm(AuthenticationForm):

class Meta:

model = CustomUser

fields = ['username', 'password']

Create Views

Create views for user registration, login, and a home page in your app's views.py:

# app1/views.py

from django.shortcuts import render, redirect

from django.contrib.auth import login, authenticate

from .forms import SignUpForm, LoginForm

def signup(request):

if request.method == 'POST':

form = SignUpForm(request.POST)

if form.is_valid():
form.save()

username = form.cleaned_data.get('username')

raw_password = form.cleaned_data.get('password1')

user = authenticate(username=username, password=raw_password)

login(request, user)

return redirect('home') # Redirect to your home page

else:

form = SignUpForm()

return render(request, 'signup.html', {'form': form})

def user_login(request):

if request.method == 'POST':

form = LoginForm(request, data=request.POST)

if form.is_valid():

user = form.get_user()

login(request, user)

return redirect('home') # Redirect to your home page

else:

form = LoginForm()

return render(request, 'login.html', {'form': form})

def home_view(request):

return render(request, "home.html")


Create Templates

Create templates for user registration, login, and the home page in your app's templates
folder:

signup.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sign Up</title>
</head>
<body>
<h2>Sign Up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign Up</button>
</form>
</body>
</html>

login.html:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Login</title>

</head>

<body>

<h2>Login</h2>

<form method="post">

{% csrf_token %}
{{ form.as_p }}

<button type="submit">Login</button>

</form>

</body>

</html>

home.html:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Home</title>

</head>

<body>

<h1>Welcome to the Home Page</h1>

</body>

</html>

Step 10: Update URLs

Update your app's urls.py to include the new views:

# app1/urls.py

from django.urls import path


from .views import signup, user_login, home_view

urlpatterns = [

path('signup/', signup, name='signup'),

path('login/', user_login, name='login'),

path('home/', home_view, name='home'),

Include these URLs in your project's urls.py:

# signup/urls.py

from django.contrib import admin

from django.urls import path, include

urlpatterns = [

path('admin/', admin.site.urls),

path('app1/', include('app1.urls')),

Step 11: Run Migrations

Run migrations to create the necessary database tables:

python manage.py makemigrations

python manage.py migrate


Step 12: Run the Development Server

Start the development server:

python manage.py runserver

Now you can access the signup and login pages at:

● Signup: http://localhost:8000/app1/signup/
● Login: http://localhost:8000/app1/login/

Once you log in, you will be redirected to the home page.

Additional Features

You can extend this setup by adding features such as:

● Email verification during signup.


● Password reset functionality.
● User profile pages.

Here's a sample Django project structure that you can provide to your students. This project is
designed to include different apps for various machine learning algorithms, such as linear
regression and logistic regression. The project allows users to upload data files, select the type
of machine learning algorithm, and navigate accordingly.

You might also like