Models, Relations, & Inheritance
Django Models
In Django, the model is the object mapped to the database.
Supported Databases
Django 3.0
and higher officially supports five databases:
- PostgreSQL
- MySQL
- SQLite
- Oracle
- MariaDB
There are also several third-party applications available if you need to connect to an unofficially supported database.
Model
Working with model field relationships
Django provides three relationship types for linking tables:
- Many–to–one
- Many–to–many
- One–to–one
A many-to-one
relationship is defined by using a ForeignKey
field, and the other two relationship types are defined using the self-explanatory ManyToManyField
and OneToOneField
. These fields are named appropriately after the relationship type that they represent.
The three field types — ForeignKey
, ManyToManyField
, and OneToOneField
.
# /becoming_a_django_entdev/chapter_3/models.py
...
class Vehicle(models.Model):
...
vehicle_model = models.ForeignKey(
VehicleModel,
on_delete = models.CASCADE,
verbose_name = 'Model',
related_name = 'model_vehicle',
blank = True,
null = True,
)
engine = models.ForeignKey(
Engine,
on_delete = models.CASCADE,
verbose_name = 'Engine',
related_name = 'engine_vehicle',
blank = True,
null = True,
)
# /becoming_a_django_entdev/chapter_3/models.py
...
class Seller(models.Model):
name = models.CharField(
verbose_name = 'Seller Name',
max_length = 150,
blank = True,
null = True,
)
vehicle = models.ManyToManyField(
Vehicle,
verbose_name = 'Vehicles',
related_name = 'vehicle_sellers',
related_query_name = 'vehicle_seller',
blank = True,
)
Customizing models
Writing methods
Writing a model method is similar to writing a Meta subclass, except instead of writing a class, we are now writing a function inside that class using the def
keyword.
The four most helpful and most used methods are defined here:
def save(self, *args, **kwargs)
def delete(self, *args, **kwargs)
def get_absolute_url(self)
def __str__(self)
Decorators
A decorator is a standard Python design pattern that allows developers to extend the functionality of an object without permanently changing the behavior of that object. The concept of decorators can be applied to virtually any class or method that exists in a project.
-
@property
A @property decorator allows us to write a method to act as a regular property of a model instance, rather than act as a function.
Extending models
Extending a model is a way to write a set of fields and methods that can be shared in many different classes. This is also known as inheritance, which is a fundamental principle of the Python language, letting us write code once and reuse it over and over again. It is also a way to reuse or modify a class provided by Django itself, such as the built-in User model, which is a very common model to extend.
Using the Django shell
Generating a SECRET_KEY variable
A SECRET_KEY
variable in Django is used as a hash to secure things, such as your sessions
, cookie storage
, password tokenization
, and all other methods of cryptographic signing that act to secure your site. Instead of using an online tool to generate this key, where the transmission either to or from that source could be compromised, you could generate your own using the Django shell.
$ python3 manage.py shell
$ from secret_key_generator import secret_key_generator
$ print(secret_key_generator.generate())
Using the Meta subclass
Model metadata is an inner class of a model called Meta.
It is not required and completely optional but it does make using Django much more useful when it is included in your models. Metadata provides all of the "other" information that is not defined in model field arguments. The settings that are defined inside this class are called meta options, and there are quite a lot to choose from.
from django.db import models
class MyModel(models.Model):
# Model fields here
class Meta:
verbose_name = "Custom Singular Name"
verbose_name_plural = "Custom Plural Name"
ordering = ['field1', '-field2']
unique_together = ['field1', 'field2']
indexes = [
models.Index(fields=['field1'], name='field1_idx'),
models.Index(fields=['field2'], name='field2_idx'),
]
permissions = [
('can_view', 'Can view records'),
('can_edit', 'Can edit records'),
]
Django auto_now
vs auto_now_add
In Django, auto_now and auto_now_add are options for DateTimeField and DateField fields in models. They are used to automatically set the field to the current date and time when an object is created or updated. Here's the difference between the two:
1. auto_now: When this option is set to True
, the field will be updated with the current date and time every time the model's save() method is called. This means that the field will always reflect the most recent time the object was saved to the database.
2. auto_now_add: When this option is set to True
, the field will be set to the current date and time when the object is first created, and it will not be updated subsequently. This is useful for fields that should have a fixed creation timestamp.
Here's an example of how they can be used in a Django model:
from django.db import models
class MyModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# Other fields...
In this example, created_at
will be set to the current timestamp when an instance of MyModel is created, and updated_at
will be updated with the current timestamp every time the instance is saved.
When to use auto_now
and auto_now_add
depends on the specific requirements of your application:
-
Use auto_now_add when you want to record the time when an object was created and you don't want this field to be updated later.
-
Use auto_now when you want to keep track of the last time an object was updated.
However, there are situations where you might not want to use these options:
-
Avoid using
auto_now
andauto_now_add
if you need to manually set these fields in some cases. For example, if you're importing data and need to set specific creation or update timestamps, using these options will override your manual settings. -
Avoid using
auto_now
if you have cases where you want to update other fields without updating the timestamp field.
In summary, auto_now
and auto_now_add
are useful shortcuts for handling timestamp fields in Django models, but you should consider your application's specific requirements and potential edge cases when deciding whether to use them.
Example of auto_now and auto_add_now
In a typical blog model scenario, you would want to record both the creation date of the blog post and the last modification date. For this purpose, you can use both auto_now_add and auto_now options for DateTimeField.
Here's how you might implement it:
from django.db import models
class Blog(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
In this model:
created_at
will automatically store the date and time when the blog post is first created.updated_at
will automatically update to the current date and time whenever the blog post is saved.
This setup ensures that you have both the creation date and the last modification date stored for each blog post. It's a common and efficient approach for most blog applications.
If you only need the creation date and don't care about the last modification date, you can just use auto_now_add=True
for the created_at
field:
class Blog(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
This simplifies the model, but you lose the ability to track when the post was last updated.
Ultimately, the best option depends on your specific requirements. If you need both creation and modification dates, the first approach is appropriate. If you only need the creation date, you can use the simplified version.
ModelAdmin class
In Django admin, readonly_fields and fields are attributes of the ModelAdmin class that allow you to customize which fields are displayed and whether they are editable in the admin interface.
attributes
- fields
- readonly_fields
- list_display
- ordering
- list_per_page
Django Category
Static choices
from django.db import models
class YourModel(models.Model):
CHOICES = (
('option1', 'Option 1'),
('option2', 'Option 2'),
('option3', 'Option 3'),
)
your_field = models.CharField(max_length=20, choices=CHOICES)
Advanced Model
Mastering Django by Nigel George 2022, chapter 9
Django’s QuerySet API provides a comprehensive array of methods and functions for working with data.
Methods that return QuerySets
Methods that Don't return QuerySets
Model Managers
A Manager is a Django class that provides the interface between database query operations and a Django model. Each Django model is provided with a default Manager named objects
.
Tips
newevent = Event.objects.get(name="Xmas Barbeque")
joneses = MyClubUser.objects.filter(last_name='Jones')
In each example, objects
is the default Manager
for the model instance.
Model Methods
Django’s Model class comes with many built-in methods. We have already used some of them — save()
, delete()
, __str__()
and others. Where manager methods add table-level functionality to Django’s models, model methods add row-level functions that act on individual instances of the model.
There are two common cases where you want to play with model methods:
- When you want to add business logic to the model by adding custom model methods; and
- When you want to override the default behavior of a built-in model method.
Reference
Becoming an Enterprise Django Developer by Michael Dinder (pg-122)