# The power of Django Models
## Introduction - Django, the D is silent
> Django makes it easier to build better Web apps more quickly and with less code.
- [Django website](https://www.djangoproject.com/)
Django is a fully featured Python web framework that can be used to build complex web applications.
Created on `2003` by web developers at the `Lawrence Journal-World`, but only publicly released on `2005`, and built on top of the `MTV`(Model-Template-View) architectural pattern, a pattern based on `MVC`(Model-View-Controller), this framework emphasizes reusability and pluggability of components making possible to develop web apps extremely fast.
### Model Template View
The `MTV` architecture is an architectural pattern applied by this framework to separate the application in layers called `Model`, `Template` and `View`.
The main goal on this framework is to ease the creation of database-driven web applications. So the main focus is on the `Model` layer.
To reach this goal Django includes a default `object-relation mapping` layer(`ORM`) that abstracts the database and ease the persistence of data into multiple databases. This is where we are going to focus.
### Django ORM or Django Models
> A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table.
- Django documentation
The model layer on Django is an implementation of the `Active Record`, a design pattern described by Martin Fowler on the book `Patterns of Enterprise Application Architecture`.
### Active Record
> An object that wraps a row in a database table or view, encapsulates
the database access, and adds domain logic on that data.
- Martin Fowler - Patterns of Enterprise Application Architecture
The `Active Record` design pattern ease the pain of developing database focused applications but it forces the developers to mix the `domain logic` with the `persistence logic` which can result into confuse implementations and unit tests.
## Basic usage
### Models and fields
To define a Django model the developer must write a class that inherit the `Model` class from the package `django.db.models`.
```python
class User(models.Model):
pass
```
A class that inherits from `Model` is capable of being mapped onto the database and also create a `table` to store the data.
Every attribute, or field, that should be mapped into the database must be an instance of the `Field` class.
Every `field` on the `model` will be a column of your database table.
Some of the most common and simple fields are:
```python
CharField - A string field, for small- to large-sized strings
TextField - A string field for large amounts of text
BooleanField - A field to store boolean logic(true/false)
DurationField - A field for storing pepriods of time
EmailField - A field that checks if a given email is vvalid
URLField = A CharField for storing URLs
UUIDField - A field capable of storing Universally Unique IDentifiers
```
```python
class User(models.Model):
name = models.CharField(max_length=32)
secondary_email = EmailField()
linkedin_profile = URLField()
created_at = models.DateField(auto_now=True, auto_now_add=True)
```
### Inserting and selecting data from the database
The Django ORM implements through the attribute `objects` what they call a `Model Manager`, an entity capable of accessing the database to interact with the data.
The `objects` attribute contains a `queryset` attribute which gives it the hability of interacting with the data base as a set of entities. We could be applying methods like `all`, `filter`, `get`, `exclude` and many others over this.
#### Creating a user profile
```python
user_profile = User(
name='Peter Griffin',
secondary_email='peter_griffin@gmail.com',
linkedin_profile='https://www.linkedin.com/in/peter_griffin/'
)
user_profile.save()
```
#### Searching for user profiles
```python
User.objects.all()
```
#### Get a user through its own id
```python
User.objects.get(id=5)
```
#### Filtering for user that has the name 'Peter'
```python
User.objects.filter(name='Peter')
```
#### Filtering for user that contain the name 'Griffin'
```python
User.objects.filter(name__contains='Griffin') # case sensitive
User.objects.filter(name__icontains='Griffin') # case insensitive
```
#### Excluding from a person that has the name 'Griffin'
```python
User.objects.all().exclude(name__contains='Griffin') # case sensitive
```
### Relations
Django ORM implements relations through the use of fields like `ForeignKey`. `OneToOneField` and `ManyToManyField`.
Using these fields the developer is capable of mapping the database tables into the entities in a fluid way.
#### Foreign Key
This field is used to create a one-to-many relation between entities. A given `User` could be related to many `Invoices`. To implement this the `Invoice` class must know the class of the `User` and reference it.
When defining a One to Many relation you must tell django the `delete` strategy in case of the entity on the "one" side got deleted. The most common to use is `CASCADE` deletion.
When defining this type of relation the field accepts an optional `related_name` argument to define a custom name of the inverse relation.
In case of not passing `related_name` the inverse relation will be created on the application side using the lowercase model name concatenated with '_set'
```python
class Invoice(models.Model):
value = models.FloatField()
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='invoices')
user = User.objects.get(id=5)
user.invoices.all()
```
#### Filtering users based on invoice attributes
```python
User.objects.filter(invoice__value=100)
```
#### Filtering user invoices
```python
user = User.objects.get(id=5)
user.invoices.filter(value__gte=100) # greater than or equal 500
user.invoices.filter(value__lte=100) # lower than or equal 500
```
## Conclusion
Using `ORM`s like the `Django ORM` can speed up the development time of your team, but can also create highly coupled code what can lead into problems when trying to scale the application or migrating to another technology.
Also tests involving the `ORM` layer tend to be complicated, the developer team must be extremely careful when using ORMs.