Django Fundamentals: Security and ORM Techniques
Published: 2023-04-04 07:46:37

## 1. Settings file

In Django, the settings file is an essential component of the project configuration. It contains various settings that determine how the project will behave, such as database connections, time zones, and static files management, among others.

<br>

### What is secret key?

The secret key is one of the settings found in the Django settings file (settings.py). It is a unique, randomly generated string that is used for cryptographic purposes, such as signing cookies, generating secure tokens, and other security-related tasks. The secret key helps protect sensitive information and keeps the web application secure.

It is crucial to keep the secret key secret, as exposing it could lead to various security vulnerabilities. In production, it is a good practice to store the secret key as an environment variable or in a secure secret management system, rather than directly in the settings.py file, to avoid accidentally leaking it in version control systems like Git.

<br>

### What are the default Django apps inside it? Are there more?

Django comes with several built-in apps that provide common functionality needed in web applications. When you create a new Django project, some of these apps are included in the default project settings under the **INSTALLED_APPS** list in the **settings.py** file. The default Django apps include:

1. **django.contrib.admin**: Provides the Django admin site, an automatically-generated interface for managing the data in your application.
2. **django.contrib.auth**: Provides authentication and authorization features such as user registration, login, and permissions management.
3. **django.contrib.contenttypes**: Allows you to create generic relations between models, enabling you to link any two models in a more flexible way.
4. **django.contrib.sessions**: Manages sessions for your application, allowing you to store data that is specific to a particular user across multiple requests.
5. **django.contrib.messages**: Enables you to show temporary, one-time notification messages to users after they perform certain actions, like form submissions.
6. **django.contrib.staticfiles**: Handles the management and serving of static files, such as CSS, JavaScript, and images.

<br>
These are the default apps provided by Django, but there are many more built-in apps available that you can add to your project depending on your needs. Some additional Django apps include:

1. **django.contrib.sites**: Allows you to manage multiple websites with a single Django project.
2. **django.contrib.humanize**: Provides a set of template filters that makes it easier to format numbers, dates, and other data in a more human-readable way.
3. **django.contrib.postgres**: Provides PostgreSQL-specific features like ArrayField, HStoreField, and other specialized database fields.
4. **django.contrib.gis**: Offers Geographic Information System (GIS) support for Django, including spatial fields and spatial querying capabilities.

To use any of these additional apps, you need to add them to the INSTALLED_APPS list in your settings.py file and configure them as needed.

<br> 

### What is middleware?

Middleware is a way to process requests and responses globally in a Django application. Middleware components are classes that are executed at various stages during the request/response processing flow. They allow you to perform operations on the incoming request before it reaches the view or on the outgoing response before it's sent back to the client.

### What are different kinds of middleware?

There are three types of middleware:

1. **View middleware**: View middleware is the lowest-level middleware. It is executed before the view is called and after the view is called, but before the response is returned to the client. View middleware is useful for tasks that need to be performed on every request, such as logging, authentication, or request throttling.
2. **Template response middleware**: Template response middleware is executed after the view is called and before the response is returned to the client. It is useful for tasks that need to be performed on every response, such as adding a header to every response.
3. **Exception middleware**: Exception middleware is executed when an exception occurs in the view. It is useful for tasks that need to be performed when an exception occurs, such as logging the exception or sending an email to the site administrator.


<br>

### CSRF

Cross-site request forgery (CSRF) is a type of attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response to the forged request.

### XSS

Cross-site scripting (XSS) is a type of attack that involves injecting malicious scripts into a web application. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. The end user's browser has no way to know that the script should not be trusted, and will execute the script. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by the browser and used with that site. These scripts can even rewrite the content of the HTML page.

### Click Jacking

Clickjacking is a type of attack that tricks a user into clicking on something different than what they perceive they are clicking on. This is done by overlaying transparent or opaque layers on top of the desired website, tricking the user into clicking on the transparent or opaque layer instead of the website itself.

<br>

### Any other middleware that is there?

There are several other built-in middleware classes that you can use in your Django project. Here's a brief overview of some key middleware:

1. **django.middleware.security.SecurityMiddleware**: This middleware adds several security-related headers to every response, such as the **X-Frame-Options** header, which prevents clickjacking attacks.
2. **django.middleware.clickjacking.XFrameOptionsMiddleware**: This middleware adds the **X-Frame-Options** header to every response, which prevents clickjacking attacks.
3. **django.middleware.csrf.CsrfViewMiddleware**: This middleware adds a CSRF token to every POST request, which prevents cross-site request forgery attacks.
4. **django.middleware.common.CommonMiddleware**: This middleware adds several security-related headers to every response, such as the **X-Content-Type-Options** header, which prevents MIME type sniffing attacks.
5. **django.middleware.clickjacking.XFrameOptionsMiddleware**: This middleware adds the **X-Frame-Options** header to every response, which prevents clickjacking attacks.
6. **django.middleware.csrf.CsrfViewMiddleware**: This middleware adds a CSRF token to every POST request, which prevents cross-site request forgery attacks.
7. **django.middleware.common.CommonMiddleware**: This middleware adds several security-related headers to every response, such as the **X-Content-Type-Options** header, which prevents MIME type sniffing attacks.

<br>

### What is (WSGI) ?

WSGI, or Web Server Gateway Interface, is a standard interface between web servers and Python web applications or frameworks. It allows for greater compatibility and interchangeability between different web servers and Python applications. WSGI was introduced as part of the PEP 333 (Python Enhancement Proposal) to create a common interface that would enable web servers to communicate with various Python web applications, regardless of the underlying framework or technology.

WSGI acts as a middleware that translates requests coming from a web server into a format that Python web applications can understand, and vice versa. By conforming to the WSGI standard, web applications can be deployed on any WSGI-compliant web server, and web servers can host any WSGI-compliant application.

<br>

## 2. Models file

In Django, models are Python classes that inherit from **django.db.models.Model**. They define the fields and behavior of the data that you want to store. Each attribute in the model class represents a field in the database table. The fields are instances of Django field classes such as **CharField, IntegerField, DateField, ForeignKey,** etc.

<br>

### What is ondelete Cascade?

**on_delete** is a parameter used in Django models when defining ForeignKey or OneToOneField relationships. It specifies what should happen when the referenced object (the target of the ForeignKey or OneToOneField) is deleted.

**CASCADE** is one of the options you can use for the **on_delete** parameter. When the **on_delete** is set to **CASCADE**, it means that when the referenced object is deleted, all related objects (those that have a ForeignKey or OneToOneField pointing to the deleted object) will also be deleted. This is useful when you want to maintain referential integrity in your database and ensure that there are no orphaned records.

<br>

### Field and Validators

Django provides various field classes that you can use to define the structure and data types of your model's attributes. These fields automatically include validation, form widgets, and database column types suitable for the data they are intended to store. Some common field types include:

- **CharField**: A character field for storing short strings.
- **TextField**: A large text field for storing longer strings.
- **IntegerField**: An integer field for storing integer values.
- **FloatField**: A floating-point field for storing decimal values.
- **DateField**: A field for storing date values (year, month, day).
- **DateTimeField**: A field for storing date and time values.
- **BooleanField**: A field for storing boolean values (True or False).
- **ForeignKey**: A field for creating a one-to-many relationship between two models.
- **OneToOneField**: A field for creating a one-to-one relationship between two models.
- **ManyToManyField**: A field for creating a many-to-many relationship between two models.

Django also provides built-in validators that can be added to fields to enforce specific constraints on the data. Validators are functions that take a value as input and raise a **ValidationError** if the value does not meet the specified criteria. Some common validators include:

- **MinValueValidator**: Validates that the value is greater than or equal to a minimum value.
- **MaxValueValidator**: Validates that the value is less than or equal to a maximum value.
- **MinLengthValidator**: Validates that the value has a minimum length.
- **MaxLengthValidator**: Validates that the value has a maximum length.
- **EmailValidator**: Validates that the value is a valid email address.
- **URLValidator**: Validates that the value is a valid URL.
- **RegexValidator**: Validates that the value matches a specified regular expression.

<br>

### Python module vs. Python class

A Python module is a file containing Python code, typically with a **.py** extension. The module can include functions, classes, and variables, as well as executable code. Modules are used to organize your code and make it more reusable and maintainable. You can import functions or classes from a module into another module, script, or the Python interpreter.

A Python class, on the other hand, is a code template for creating objects. It defines the structure, attributes, and methods that instances of the class will have. Classes are used in object-oriented programming to encapsulate related data and behavior and promote code reuse and modularity. Instances of a class are individual objects that have their own set of attributes and can use the methods defined in the class.

In summary, a module is a file containing Python code (which can include classes), while a class is a template for creating objects with a specific structure and behavior.

<br>

## 3. Django ORM

Django ORM (Object-Relational Mapping) is a powerful and high-level abstraction over the database that allows you to interact with the database using Python objects and methods instead of writing raw SQL queries. The ORM translates the Python code you write into SQL queries, which are then executed on the database. This approach makes it easier to write, read, and maintain database-related code and allows you to switch between different databases with minimal code changes.

<br>

### Using ORM queries in Django Shell

The Django shell is an interactive Python shell that has your Django project's environment and settings pre-loaded. You can use the Django shell to interact with your models, execute ORM queries, and inspect the results. To start the Django shell, run the following command in your terminal:

```sh
python manage.py shell
```
Inside the shell, you can import your models and perform ORM queries like creating, retrieving, updating, or deleting records. For example:
```py
from myapp.models import MyModel

# Create a new record
my_instance = MyModel(name="Example", value=42)
my_instance.save()

# Retrieve records
all_instances = MyModel.objects.all()

# Update a record
my_instance.value = 50
my_instance.save()

# Delete a record
my_instance.delete()
```

<br>

### Turning ORM to SQL in Django Shell

Django ORM queries can be translated into raw SQL by using the query attribute of a queryset. For example:

```py
from myapp.models import MyModel

queryset = MyModel.objects.filter(name="Example")
sql_query = str(queryset.query)
print(sql_query)
```

<br>

### What are Aggregations?

**Aggregations** in Django ORM are operations that perform calculations on a set of records and return a single value, such as counting the number of records, calculating the average, sum, minimum, or maximum of a field. Aggregations can be used to perform complex calculations on the data stored in your models without having to retrieve all records and process them in Python. You can use the **aggregate()** function along with aggregation classes like **Count, Avg, Sum, Min, and Max** from **django.db.models**. For example:

```py
from django.db.models import Count, Avg
from myapp.models import MyModel

# Count the number of records
record_count = MyModel.objects.aggregate(Count('id'))

# Calculate the average value of the 'value' field
average_value = MyModel.objects.aggregate(Avg('value'))
```

<br>

### What are Annotations?

**Annotations** in Django ORM are a way to add extra fields to each record in a queryset by performing calculations based on the values of other fields or aggregating data from related models. Annotations can be used for tasks like calculating the total price of items in an order or adding a field with a boolean value that indicates if a certain condition is met. You can use the **annotate()** function along with expressions like **F, ExpressionWrapper**, and **aggregation** classes. For example:

```py
from django.db.models import F, ExpressionWrapper, BooleanField
from myapp.models import MyModel

# Annotate each record with a 'is_value_greater_than_10' field
annotated_queryset = MyModel.objects.annotate(
    is_value_greater_than_10=ExpressionWrapper(F('value') > 10, output_field=BooleanField())
)
```

<br>

### What is a migration file? Why is it needed?

A migration file is a file that contains the instructions for making changes to the database schema. It is generated automatically by Django when you make changes to your models. You can use the **makemigrations** command to generate a migration file for your models. For example:

```sh
python manage.py makemigrations
```

The migration file contains the instructions for creating, modifying, or deleting the database tables and columns that correspond to your models. You can use the **migrate** command to apply the changes to the database. For example:

```sh
python manage.py migrate
```

Migration files are needed for several reasons:

1. **Version Control**: They help to maintain a version control system for the database schema, allowing developers to easily manage and track changes to the schema over time.

2. **Collaboration**: Migration files make it easier for teams of developers to collaborate on a project, since each developer can create their own migration file for the changes they made, avoiding conflicts and keeping everyone on the same page.

3. **Deployment**: When deploying an application to a new environment, migration files ensure that the database schema can be created or updated in a consistent and controlled manner.

<br>

### What are SQL transactions? (non ORM concept)

**SQL transactions** are a way to execute a series of operations on a database as a single unit of work. Transactions follow the ACID properties: Atomicity, Consistency, Isolation, and Durability. These properties ensure that the database remains in a consistent state even when multiple users are accessing it simultaneously, or when unexpected errors occur.

1. **Atomicity**: A transaction is atomic, meaning that either all of its operations are executed successfully, or none of them are. If any operation fails, the entire transaction is rolled back, and the database returns to its state before the transaction started.

2. **Consistency**: A transaction ensures that the database moves from one consistent state to another. Once a transaction is committed, all changes made during that transaction are permanent and the database is in a consistent state.

3. **Isolation**: Transactions are isolated from each other, which means that the operations of one transaction are not visible to other transactions until the transaction has been committed.

4. **Durability**: Once a transaction is committed, its changes to the database are permanent, even in the case of system failures.

<br>

### What are atomic transactions?

**Atomic transactions,** as the name suggests, are a subset of SQL transactions that specifically emphasize the atomicity property. The term "atomic" refers to the all-or-nothing nature of these transactions. In an atomic transaction, if any operation within the transaction fails, the entire transaction is rolled back, and the database remains unchanged. This ensures that the database is never left in an inconsistent state, providing a higher level of reliability and data integrity.

---
## REFERENCES
* [Django documentation Secret](https://docs.djangoproject.com/en/3.2/topics/settings/)
* [Default Django Apps](https://docs.djangoproject.com/en/3.2/ref/applications/)
* [Middleware](https://docs.djangoproject.com/en/3.2/topics/http/middleware/)
* [Django Security: CSRF](https://docs.djangoproject.com/en/3.2/ref/csrf/)
* [Django Security: XSS](https://docs.djangoproject.com/en/3.2/topics/security/#cross-site-scripting-xss-protection)
* [Django Security: Clickjacking](https://docs.djangoproject.com/en/3.2/topics/security/#clickjacking-protection)
* [Other middleware](https://docs.djangoproject.com/en/3.2/topics/security/#other-security-middleware)
* [WSGI](https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/)
* [Django ORM, Queries, and Migrations](https://docs.djangoproject.com/en/3.2/topics/db/queries/)
* [SQL Transactions and Atomic Transactions](https://docs.djangoproject.com/en/3.2/topics/db/transactions/)