Click to share! ⬇️

Django models are a central part of every Django application. They define the structure and behavior of the data stored in your Django project. Models in Django are defined using Python classes that subclass django.db.models.Model. Each model class defines a set of fields, which represent the data stored in the model.

For example, here is a simple model that defines a Person model with a name field and an age field:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

Once you have defined your models, Django will automatically create a database schema for you based on the fields you have defined. You can then use the Django ORM (Object-Relational Mapper) to query and manipulate the data stored in your models.

In this tutorial, we will look at how to define models, use different field types, set model options, use model managers, use model inheritance, create custom model managers and querysets, and use model transactions in Django.

Defining A Model

To define a model in Django, you will need to create a Python class that subclasses django.db.models.Model and defines a set of fields.

Here is an example of a simple model definition:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

In this example, we have defined a Person model with a name field and an age field. The name field is a CharField, which is a field that stores character data, and the age field is an IntegerField, which is a field that stores integer data.

Once you have defined your model, you will need to run the migrate command to create the corresponding database tables:

python manage.py migrate

This will create a new table in the database for the Person model, with columns for the name and age fields.

You can then use the Django ORM to query and manipulate the data stored in your model. For example, you can use the Person.objects attribute to access the model’s manager and create, retrieve, update, and delete instances of the model:

# Create a new Person instance
person = Person(name='John', age=30)
person.save()

# Retrieve a Person instance
person = Person.objects.get(name='John')

# Update a Person instance
person.age = 31
person.save()

# Delete a Person instance
person.delete()

Field Types

You can use different field types to store different types of data in your models. Here is a list of the most commonly used field types in Django:

  • CharField: A field that stores character data. You can specify the maximum length of the field using the max_length parameter.
  • TextField: A field that stores long text data.
  • IntegerField: A field that stores integer data.
  • FloatField: A field that stores floating-point data.
  • BooleanField: A field that stores boolean data (True or False).
  • DateField: A field that stores a date (without a time).
  • TimeField: A field that stores a time (without a date).
  • DateTimeField: A field that stores a date and time.
  • DecimalField: A field that stores decimal data.
  • EmailField: A field that stores an email address.
  • URLField: A field that stores a URL.
  • FileField: A field that stores a file.
  • ImageField: A field that stores an image file.

You can specify additional options for each field type, such as null, blank, and default. You can also use field validators to ensure that the data stored in the field is valid.

Model Options

In Django, you can specify various options for your models using the class Meta inner class. The Meta class allows you to set options such as the model’s database table name, its ordering, and whether it should be abstract or have a singleton design.

Here is an example of how to use the Meta class to set options for a model:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

    class Meta:
        # Set the database table name
        db_table = 'my_person_table'
        # Set the ordering of the model
        ordering = ['age']
        # Make the model abstract
        abstract = True

In this example, we have set the database table name to my_person_table, the ordering to be based on the age field, and made the model abstract.

The db_table option allows you to specify a custom name for the database table that will be used to store the model’s data. By default, Django will use a default table name that is based on the model’s name.

The ordering option allows you to specify the default ordering for the model’s objects. By default, the ordering is ascending. You can use the '-field_name' syntax to specify descending ordering.

The abstract option allows you to specify that the model should be abstract, which means that it cannot be used to create database table and cannot be used to create instances of the model. Abstract models are often used as base classes for other models.

Model Manager

A model manager is an interface through which you can interact with the data stored in a model. By default, Django provides a model manager called objects for every model. The objects manager provides methods for creating, retrieving, updating, and deleting objects of the model.

Here is an example of how to use the objects manager to query and manipulate data in a model:

from myapp.models import Person

# Create a new Person object
person = Person(name='John', age=30)
person.save()

# Retrieve all Person objects
people = Person.objects.all()

# Retrieve a single Person object
person = Person.objects.get(name='John')

# Update a Person object
person.age = 31
person.save()

# Delete a Person object
person.delete()

In addition to the objects manager, you can also define custom model managers to provide additional methods for querying and manipulating data in your models.

To define a custom model manager, you will need to create a subclass of django.db.models.Manager and set it as the objects attribute of your model. You can then define custom methods on the manager class to provide additional functionality.

Here is an example of how to define a custom model manager:

from django.db import models

class PersonManager(models.Manager):
    def get_adults(self):
        return self.filter(age__gte=18)

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

    objects = PersonManager()

In this example, we have defined a custom model manager called PersonManager that provides a get_adults method for retrieving all Person objects with an age of 18 or older. We have then set the PersonManager as the default manager for the Person model using the objects attribute.

You can then use the get_adults method like any other queryset method:

adults = Person.objects.get_adults()

You can also define custom querysets by subclassing django.db.models.query.QuerySet and specifying the custom queryset as the QuerySet attribute of the custom manager. This allows you to define custom behavior for the querysets returned by the manager’s methods.

Model Inheritance

You can use model inheritance to create a parent-child relationship between two or more models. This allows you to define common fields and behavior in a base model, and then create derived models that inherit from the base model and add additional fields and behavior.

There are three types of model inheritance in Django: abstract base classes, multi-table inheritance, and proxy models.

Abstract base classes:

Abstract base classes are used to define an abstract base model that cannot be used to create database tables or create instances of the model. Abstract base classes are often used as a way to define common fields and behavior that can be shared by multiple models.

To define an abstract base class, you will need to set the abstract attribute of the Meta inner class to True.

Here is an example of how to define an abstract base class:

from django.db import models

class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class Person(BaseModel):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

In this example, the BaseModel is an abstract base class that defines created_at and updated_at fields. The Person model inherits from BaseModel and adds a name and age field.

Multi-table inheritance:

Multi-table inheritance is used to define a base model and one or more derived models that each have their own database table. This allows the derived models to have additional fields and behavior that are specific to them.

To use multi-table inheritance, you will need to specify the BaseModel as the parent class using the models.Model syntax.

Here is an example of how to use multi-table inheritance:

class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Person(BaseModel):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

class Student(Person):
    student_id = models.CharField(max_length=100)
    major = models.CharField(max_length=100)

In this example, the Person model is the base model and the Student model is the derived model. The Student model inherits from the Person model and adds a student_id and major field.

Proxy models:

Proxy models are used to define a model that shares the same database table as another model. This allows you to create a new model that has the same fields and behavior as the original model, but with a different name and possibly additional behavior. To define a proxy model, you will need to specify the original model as the parent class using the models.Model syntax, and set the proxy attribute of the Meta inner class to True.

Here is an example of how to define a proxy model:

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

class Employee(Person):
    employee_id = models.CharField(max_length=100)
    salary = models.DecimalField(max_digits=10, decimal_places=2)

    class Meta:
        proxy = True

In this example, the Person model is the original model and the Employee model is the proxy model. The Employee model inherits from the Person model and adds an employee_id and salary field. The proxy attribute is set to True, which indicates that the Employee model is a proxy model.

Proxy models do not have their own database table, and all instances of the proxy model will be stored in the same database table as the original model. This allows you to create a new model that has the same fields and behavior as the original model, but with a different name and possibly additional behavior.

Custom Model Managers And Querysets

Custom model managers are defined as subclasses of django.db.models.Manager and are set as the objects attribute of a model. Custom model managers can define custom methods that provide additional querying functionality beyond the default methods provided by the objects manager.

Custom querysets are defined as subclasses of django.db.models.query.QuerySet and are specified as the QuerySet attribute of a custom model manager. Custom querysets allow you to define custom behavior for the querysets returned by the manager’s methods.

Here is an example of how to define a custom model manager and custom queryset:

from django.db import models

class PersonQuerySet(models.query.QuerySet):
    def adults(self):
        return self.filter(age__gte=18)

class PersonManager(models.Manager):
    def get_queryset(self):
        return PersonQuerySet(self.model, using=self._db)

    def adults(self):
        return self.get_queryset().adults()

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

    objects = PersonManager()

In this example, we have defined a custom queryset called PersonQuerySet that provides an adults method for filtering Person objects with an age of 18 or older. We have then defined a custom model manager called PersonManager that has a get_queryset method that returns an instance of the PersonQuerySet. The PersonManager also has an adults method that calls the adults method on the PersonQuerySet.

You can then use the PersonManager.adults method like any other queryset method:

adults = Person.objects.adults()

Custom model managers and custom querysets can be useful for encapsulating complex querying logic and providing a clean and intuitive interface for interacting with the data in your models.

Model Transactions

A transaction is a set of database operations that are executed as a single unit of work. Transactions allow you to ensure that your database updates are atomic, consistent, isolated, and durable (ACID).

To use transactions in Django, you will need to use the atomic decorator or context manager provided by the django.db.transaction module.

Here is an example of how to use the atomic decorator to wrap a block of code in a transaction:

from django.db import transaction

@transaction.atomic
def update_data():
    data1 = Data.objects.get(id=1)
    data1.value = 'new value'
    data1.save()

    data2 = Data.objects.get(id=2)
    data2.value = 'new value'
    data2.save()

In this example, the update_data function updates two Data objects and wraps the updates in a transaction. If either of the updates fail, the transaction will be rolled back and the updates will not be applied to the database.

You can also use the atomic context manager to wrap a block of code in a transaction:

from django.db import transaction

def update_data():
    with transaction.atomic():
        data1 = Data.objects.get(id=1)
        data1.value = 'new value'
        data1.save()

        data2 = Data.objects.get(id=2)
        data2.value = 'new value'
        data2.save()

In this example, the update_data function updates two Data objects and wraps the updates in a transaction using the atomic context manager. If either of the updates fail, the transaction will be rolled back and the updates will not be applied to the database.

Transactions are useful for ensuring the consistency and integrity of your data, especially when you are performing multiple updates that need to be treated as a single unit of work.

Click to share! ⬇️