Django - Models
Django - Models
Section titled “Django - Models”A model in Django is the definitive source of information about your data. It’s a Python class that represents a table (in relational databases) or a collection (in NoSQL databases like MongoDB) in your database. Each attribute of the model class maps to a database field (column).
Models are typically defined in an application’s models.py file (e.g., myapp/models.py). Django uses these model definitions to:
- Automatically generate database schema (e.g.,
CREATE TABLEstatements) through its migration system. - Provide a high-level Python API (the ORM - Object-Relational Mapper) for creating, retrieving, updating, and deleting (CRUD) database records.
Creating a Model
Section titled “Creating a Model”Let’s define a simple model to represent companies in an imaginary directory.
from django.db import models
class Company(models.Model): # Fields define the columns in the database table name = models.CharField(max_length=100, unique=True, help_text="Name of the company") website = models.URLField(max_length=200, blank=True, help_text="Company website URL (optional)") email = models.EmailField(max_length=100, help_text="Contact email address") phone_number = models.CharField(max_length=20, blank=True, help_text="Contact phone number (optional)") founded_date = models.DateField(null=True, blank=True, help_text="Date the company was founded") is_active = models.BooleanField(default=True, help_text="Is the company currently active?") # Automatically added fields (by Django): # id = models.AutoField(primary_key=True) # Default primary key
class Meta: db_table = "companies" # Optional: Explicitly name the database table verbose_name = "Company" # Optional: Human-readable singular name verbose_name_plural = "Companies" # Optional: Human-readable plural name ordering = ['name'] # Optional: Default ordering when querying
def __str__(self): # String representation used in admin and shell return self.nameKey Points:
- Every model is a Python class that inherits from
django.db.models.Model. - Each attribute represents a database field, defined using
models.Fieldtypes (e.g.,CharField,URLField,IntegerField,DateField,BooleanField,ForeignKey, etc.). - Common field options include
max_length,unique,blank(validation-related, allows empty value in forms),null(database-related, allowsNULLin DB),default,help_text. - Django automatically adds an auto-incrementing primary key field named
idunless you specifyprimary_key=Trueon another field. - The inner
Metaclass is optional and allows you to configure model metadata like the database table name (db_table), default ordering (ordering), and human-readable names (verbose_name,verbose_name_plural). - The
__str__()method defines a human-readable representation of the object, which is very useful in the Django admin and shell.
You can find a comprehensive list of model fields and options in the Django documentation: https://docs.djangoproject.com/en/stable/ref/models/fields/
Activating Models: Migrations
Section titled “Activating Models: Migrations”Defining a model class doesn’t automatically create the corresponding database table. You need to use Django’s migration system:
-
Ensure your app is in
INSTALLED_APPS: Add'myapp'or'myapp.apps.MyappConfig'toINSTALLED_APPSin your project’ssettings.py. -
Create migrations: This command analyzes changes in your
models.py(compared to previous migrations) and creates migration files in themyapp/migrations/directory.
python manage.py makemigrations myapp- Apply migrations: This command reads the migration files and applies the changes to your database schema (e.g., creates the
companiestable).
python manage.py migrateYou need to run makemigrations and migrate whenever you make changes to your models (add/remove fields, change field types, modify options, etc.).
Manipulating Data (CRUD Operations)
Section titled “Manipulating Data (CRUD Operations)”Django provides a powerful database-abstraction API (the ORM) to interact with your models. You access this API through a Manager attached to your model class, typically called objects.
Let’s see CRUD examples using the Django shell (python manage.py shell) or within a view:
# Assuming you run 'python manage.py shell'from myapp.models import Companyimport datetime
# === CREATE ===# Method 1: Create and save in two stepsc1 = Company(name="TechCorp", email="contact@techcorp.com", website="https://techcorp.com")c1.save() # Executes the INSERT SQL query
# Method 2: Create and save in one step using the managerc2 = Company.objects.create( name="Innovate Ltd", email="info@innovate.com", phone_number="123-456-7890", founded_date=datetime.date(2020, 1, 1))
print(f"Created company: {c1}")print(f"Created company: {c2}")
# === RETRIEVE / READ ===# Get all companiesall_companies = Company.objects.all() # Returns a QuerySet (lazy)print(f"\nAll Companies ({all_companies.count()}):")for company in all_companies: print(f"- {company.name} (ID: {company.id})")
# Get a specific company by primary key (id)try: techcorp = Company.objects.get(pk=c1.id) # Or get(id=c1.id) print(f"\nFound by PK: {techcorp.name}")except Company.DoesNotExist: print(f"\nCompany with pk={c1.id} not found.")
# Get using other field lookups (returns one or raises DoesNotExist / MultipleObjectsReturned)try: innovate = Company.objects.get(name="Innovate Ltd") print(f"Found by name: {innovate.name}")except Company.DoesNotExist: print("\nInnovate Ltd not found.")
# Filter to get multiple companies (returns a QuerySet)active_companies = Company.objects.filter(is_active=True)print(f"\nActive companies ({active_companies.count()}):")for company in active_companies: print(f"- {company.name}")
# More complex lookups (field__lookuptype)recent_companies = Company.objects.filter(founded_date__year__gte=2020) # Founded in or after 2020print(f"\nRecent companies ({recent_companies.count()}): {list(recent_companies)}")
# Exclude companiesnon_tech_companies = Company.objects.exclude(name__icontains="tech") # Case-insensitive containsprint(f"\nNon-tech companies: {list(non_tech_companies)}")
# Ordering resultscompanies_by_name_desc = Company.objects.order_by('-name') # Descending orderprint(f"\nOrdered by name DESC: {list(companies_by_name_desc)}")
# === UPDATE ===# Get an object, modify attributes, and savetry: company_to_update = Company.objects.get(name="TechCorp") company_to_update.website = "https://new-techcorp.com" company_to_update.is_active = False company_to_update.save() # Executes the UPDATE SQL query print(f"\nUpdated TechCorp: Website='{company_to_update.website}', Active={company_to_update.is_active}")except Company.DoesNotExist: print("\nTechCorp not found for update.")
# Update multiple objects at once (more efficient, bypasses save() method)num_updated = Company.objects.filter(founded_date__isnull=True).update(is_active=False)print(f"\nSet {num_updated} companies with no founding date to inactive.")
# === DELETE ===# Get an object and delete ittry: company_to_delete = Company.objects.get(name="Innovate Ltd") delete_result = company_to_delete.delete() # Executes the DELETE SQL query print(f"\nDeleted Innovate Ltd. Result: {delete_result}")except Company.DoesNotExist: print("\nInnovate Ltd not found for deletion.")
# Delete multiple objects at once (more efficient)delete_result_multi = Company.objects.filter(is_active=False).delete()print(f"\nDeleted inactive companies. Result: {delete_result_multi}")Model Relationships
Section titled “Model Relationships”Models can be linked together to represent relationships between data:
-
ForeignKey(Many-to-One): The most common type. Links one model instance to another. Example: AnEmployeemodel could have aForeignKeyto aCompanymodel (many employees belong to one company). -
OneToOneField(One-to-One): Similar toForeignKey, but ensures that each instance on one side of the relationship is linked to at most one instance on the other side. Example: AUserProfilemodel might have aOneToOneFieldto Django’s built-inUsermodel. -
ManyToManyField(Many-to-Many): Links instances of one model to multiple instances of another (and vice-versa). Example: APostmodel and aTagmodel could have aManyToManyField(one post can have many tags, one tag can be applied to many posts). Django automatically creates an intermediate database table for this.
Example with ForeignKey:
from django.db import models
# Assuming Company model from above exists
class Employee(models.Model): name = models.CharField(max_length=100) email = models.EmailField(unique=True) # Link to Company (Many employees -> One company) company = models.ForeignKey( Company, on_delete=models.CASCADE, # What happens when the referenced Company is deleted? related_name='employees' # How to refer back from Company to Employee ) start_date = models.DateField()
class Meta: ordering = ['company', 'name']
def __str__(self): return f"{self.name} ({self.company.name})"
# --- After defining/modifying models, run: ---# python manage.py makemigrations myapp# python manage.py migrate
# --- Example Usage (in shell or view) ---# from myapp.models import Company, Employee
# # Assuming company 'c1' exists (TechCorp)# c1 = Company.objects.get(name='TechCorp')
# # Create employees for TechCorp# emp1 = Employee.objects.create(name='Alice', email='alice@techcorp.com', company=c1, start_date='2022-08-15')# emp2 = Employee.objects.create(name='Bob', email='bob@techcorp.com', company=c1, start_date='2023-01-10')
# # Accessing the related company from an employee# print(f"{emp1.name}'s company: {emp1.company.name}")
# # Accessing all employees for a company (using related_name)# print(f"Employees at {c1.name}:")# for emp in c1.employees.all(): # Uses the related_name 'employees'# print(f"- {emp.name}")
# # Filtering employees based on company attributes (double underscore lookup)# techcorp_employees = Employee.objects.filter(company__name='TechCorp')# print(f"Query for TechCorp employees: {list(techcorp_employees)}")Key ForeignKey arguments:
on_delete: Specifies what happens when the referenced object (theCompany) is deleted. Common choices:models.CASCADE(delete employees too),models.PROTECT(prevent deletion if employees exist),models.SET_NULL(set employee’s company field toNULL, requiresnull=Trueon the field),models.SET_DEFAULT(set to default value, requiresdefaulton the field).related_name: The name used to access the set of related objects from the target model (e.g.,company_instance.employees.all()). If omitted, Django usesmodelname_set(e.g.,employee_set).
Models are a cornerstone of Django development, providing structure to your data and a powerful API for interaction.
Further Reading:
- Django Models Documentation: https://docs.djangoproject.com/en/stable/topics/db/models/
- Making Queries (QuerySet API): https://docs.djangoproject.com/en/stable/topics/db/queries/
- Model Field Reference: https://docs.djangoproject.com/en/stable/ref/models/fields/
- Model Meta Options: https://docs.djangoproject.com/en/stable/ref/models/options/