Understanding Django ORM

Mary-Kate Olsen
Release: 2024-10-08 20:11:02
Original
420 people have browsed it

Understanding Django ORM

What is ORM?

Object-relational mapping(ORM) is a feature in Django that allows us to interact with databases using Python code without writing SQL queries. The ORM translates CRUD operations into SQL under the hood, enabling easy creation, retrieval, updating, and deletion of database objects.

Working with ORM

In Django, a model class represents a database table, and an instance of that class represents a record in the table.

Every model has at least one Manager, which is called objects. We can retrieve records from the database through this manager, resulting in a QuerySet.

QuerySets are lazy, meaning that results aren't fetched until explicitly requested.

Common QuerySet methods
filter(): Retrieve records matching certain criteria.
all(): Retrieve all records.
order_by(): Order records based on specific fields.
distinct(): Return unique records.
annotate(): Add aggregate values to each record.
aggregate(): Calculate a value from a queryset.
defer(): Load only some fields of a model, deferring others.

Advanced ORM Features

Q and F Objects allow for complex queries and efficient database-level operations. We can use 'Q' for queries that involve OR conditions, while 'F' allows you to reference model fields directly in queries.

from django.db.models import Q, F

# Using Q to filter published posts or created after a specific date
posts = Post.objects.filter(Q(status='published') | Q(created_at__gte='2024-01-01'))

# Using F to compare fields within a model (e.g., for a discount calculation)
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    discounted_price = models.DecimalField(max_digits=10, decimal_places=2)

# Retrieve products where discounted price is less than price
discounted_products = Product.objects.filter(discounted_price__lt=F('price'))
Copy after login

Query Expressions (referencing model fields) and Database Functions (applying SQL-like functions) both allow us to perform operations at the database level instead of pulling data into Python for processing. This helps optimize queries and reduce database load.

from django.db.models import Count, Max

# Count the number of posts for each status
status_count = Post.objects.values('status').annotate(count=Count('id'))

# Get the latest created post
latest_post = Post.objects.aggregate(latest=Max('created_at'))

Copy after login

Custom managers let us add extra manager methods or modify the QuerySet the manager initially returns.

class PublishedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(status='published')

class Post(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()
    status = models.CharField(max_length=50)
    created_at = models.DateTimeField(auto_now_add=True)

    objects = models.Manager()  # Default manager
    published = PublishedManager()  # Custom manager for published posts

# Use the custom manager to get published posts
published_posts = Post.published.all()

Copy after login

ContentType is a model which is useful for creating generic relationships between models without specifying them with direct foreign keys. Common use cases include comments or tags that need to be attached to different types of models.

from django.contrib.contenttypes.models import ContentType

# Example model for comments
class Comment(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    text = models.TextField()

# Creating a comment for a Post instance
post = Post.objects.get(id=1)
comment = Comment.objects.create(
    content_type=ContentType.objects.get_for_model(Post),
    object_id=post.id,
    text='Great post!'
)
Copy after login

Transactions bundle database operations as a single unit ensuring data consistency. We can use the @transaction.atomic decorator or the transaction.atomic() context manager to wrap code in a transaction block.

from django.db import transaction

# Using a transaction block
with transaction.atomic():
    post = Post.objects.create(title='New Post', content='Content here...', status='published')
    # Any other database operations will be part of this transaction
Copy after login

Django allows executing raw SQL queries for complex query where you need flexibility. However, it should be used with caution.

from django.db import connection

def get_published_posts():
    with connection.cursor() as cursor:
        cursor.execute("SELECT * FROM blog_post WHERE status = %s", ['published'])
        rows = cursor.fetchall()
    return rows
Copy after login

Conclusion

Django's ORM simplifies database interactions by providing a high-level API for working with models, managers, and queries. Understanding and utilizing these features can greatly enhance your productivity and the performance of your applications.

The above is the detailed content of Understanding Django ORM. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template