Django MongoDB Backend

repository·main·Indexed 42 days ago

https://github.com/mongodb/django-mongodb-backend

A database backend for Django that uses PyMongo to enable connections to MongoDB databases. It translates Django ORM queries into MongoDB Aggregation Pipelines and MQL, providing support for MongoDB-specific extensions, transactions via sessions, and Client-Side Field Level Encryption (CSFLE). Note that DB-API style cursors, prefetch_related(), and extra() are not supported.

Tokens
42.3K
Snippets
134
Records
200
Agent score
52%

What's inside django-mongodb-backend

  1. Explore Django MongoDB Backend documentation topics

    main

    The documentation is organized into several key areas to help you build MongoDB-backed Django applications:

    Models and Database

    • Fields, Querysets, and Models: Reference material for defining data structures and querying.
    • Indexes and Constraints: Managing MongoDB indexes and Django constraints.
    • Embedded Models: Guidance on using embedded document patterns.
    • Transactions: How to handle ACID transactions within MongoDB.
    • GIS: Support for Geographic Information Systems.

    Forms

    • Forms Reference: Documentation on how MongoDB-backed models interact with Django forms.

    MongoDB Specific Features

    • Queryable Encryption: How to use encrypted fields for enhanced security.
    • Backend Settings: Specific configuration options for the Django MongoDB Backend.
    • System Checks: A reference list of system checks performed by the backend.
  2. Encrypt embedded models

    main

    There are two strategies for encrypting embedded models in Django MongoDB Backend:

    1. Encrypt the entire subdocument: Use EncryptedEmbeddedModelField or EncryptedEmbeddedModelArrayField. When using this method, the embedded model cannot contain any individual encrypted fields. This approach prevents querying any specific fields within the subdocument.

    2. Encrypt selected fields of a subdocument: Use a standard EmbeddedModelField and define specific encrypted fields (e.g., EncryptedCharField) within the embedded model class. This allows you to query the specific encrypted fields while keeping the rest of the subdocument structure accessible.

    Limitation: MongoDB does not support encrypting selected fields within an EmbeddedModelArrayField.

    # Strategy 2: Encrypting selected fields
    class Address(models.Model):
        street = models.CharField(max_length=100) # Plaintext
        zip_code = EncryptedCharField(max_length=10) # Encrypted
    
    class User(models.Model):
        address = EmbeddedModelField(Address)
  3. Behavior of search index creation in migrations

    main
    MongoDB creates search indexes asynchronously. However, when using Django's AddIndex or RemoveIndex operations in migrations, the django-mongodb-backend will wait until the index is fully created or deleted before proceeding. This ensures database consistency for subsequent migration steps, though the wait time depends on the collection size.
  4. Handle NULL values in Unique constraints

    main

    By default, unique constraints in django-mongodb-backend (whether defined via Field.unique, Meta.unique_together, or UniqueConstraint) treat NULL values as distinct. This allows multiple documents to contain a NULL value for the constrained field.

    To restrict the database so that only one document can have a NULL value, use a django.db.models.UniqueConstraint and set nulls_distinct=False.

    from django.db import models
    
    class MyModel(models.Model):
        email = models.EmailField(null=True)
    
        class Meta:
            constraints = [
                models.UniqueConstraint(
                    fields=['email'],
                    name='unique_email_including_null',
                    nulls_distinct=False
                )
            ]
  5. Precision and range limitations for DateTime and Duration fields

    main

    When using specific Django fields with this backend, be aware of the following precision and storage characteristics:

    • DateTimeField: Limited to millisecond precision (unlike the microsecond precision used by many other databases).
    • DurationField: Stores values as milliseconds rather than microseconds.
  6. Use django_mongodb_backend.transaction.atomic for transactions

    main

    Because MongoDB transactions have specific limitations, the standard django.db.transaction.atomic functions as a no-op. To use transactions with the Django MongoDB Backend, you must use django_mongodb_backend.transaction.atomic.

    Transactions require MongoDB to be configured as a replica set or a sharded cluster. Outside of an atomic block, the backend operates in autocommit mode, where every query is immediately committed.

    from django_mongodb_backend import transaction
    
    @transaction.atomic
    def my_transactional_view(request):
        # This code executes inside a transaction.
        do_stuff()
  7. Combine SearchExpressions using bitwise operators

    main

    All expressions that subclass SearchExpression can be combined using Python's bitwise operators to create more readable search logic:

    • & → and logic
    • | → or logic
    • ~ → not logic (unary operator)

    Note: SearchVector expressions cannot be combined using these operators and will raise an error if attempted.

    from django_mongodb_backend.expressions import SearchText
    
    # Combine expressions using & and ~
    expr = SearchText("headline", "mongodb") & ~SearchText("body", "deprecated")
    Article.objects.annotate(score=expr)
  8. Understand persistent connections in Django MongoDB Backend

    main

    Persistent connections are enabled by default in the Django MongoDB Backend. This avoids the overhead of reestablishing a connection to the database for every HTTP request.

    Note that the standard Django setting CONN_MAX_AGE is unnecessary and has no effect because the backend does not respond to Django's standard connection-closing API (django.db.connection.close()).

  9. Configure SplitArrayField trailing null behavior

    main

    The remove_trailing_nulls argument in SplitArrayField controls how blank values at the end of the array are handled.

    • remove_trailing_nulls=False (default): Every value from the repeated fields is stored (as the field type or None).
    • remove_trailing_nulls=True: Any trailing values that are blank are stripped from the resulting list.

    Behavior with required=True fields: If the base_field is required but remove_trailing_nulls=True, null values are only permitted at the end of the sequence and will be stripped. If a null value appears in the middle, a ValidationError is raised.

    # Example: size=3, remove_trailing_nulls=True
    # Input: ["1", "2", ""] -> Output: [1, 2]
    # Input: ["1", "", "3"] -> ValidationError (middle value missing)
  10. Improve performance of relational field queries

    main

    Querying across relational fields like ForeignKey and ManyToManyField in MongoDB can be slow because the backend uses MongoDB's $lookup operator, which does not perform well with large collections.

    To optimize performance, follow the best practice of using embedded models instead of relational links when modeling data in MongoDB.

  11. Querying PolymorphicEmbeddedModelArrayField

    main

    You can query into a PolymorphicEmbeddedModelArrayField using the same syntax and operators as a standard EmbeddedModelArrayField.

    Note on filtering: If you filter on a field that is not shared among all possible embedded models in the array, the query will only return parent objects that contain embedded models possessing those specific fields.