Skip to content

DOCSP-46321: CRUD operations #144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions snooty.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ sharedinclude_root = "https://raw.githubusercontent.com/10gen/docs-shared/main/"
driver-short = "PyMongo"
driver-long = "PyMongo, the MongoDB synchronous Python driver,"
driver-async = "PyMongo Async"
django-odm = "Django MongoDB Backend"
language = "Python"
mdb-server = "MongoDB Server"
mongo-community = "MongoDB Community Edition"
Expand Down
271 changes: 271 additions & 0 deletions source/interact-data/crud.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
.. _django-crud:

=======================
Perform CRUD Operations
=======================

.. contents:: On this page
:local:
:backlinks: none
:depth: 2
:class: singlecol

.. facet::
:name: genre
:values: reference

.. meta::
:keywords: insert, modify, read, write, code example

Overview
---------

In this guide, you can learn how to use {+django-odm+} to run
create, read, update, and delete (CRUD) operations on your MongoDB
collection.

You can use methods provided by the Django ``QuerySet`` API to run
CRUD operations. To run these operations, you can call ``QuerySet`` methods
on your model's ``Manager``. The ``Manager`` class handles database
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
CRUD operations. To run these operations, you can call ``QuerySet`` methods
on your model's ``Manager``. The ``Manager`` class handles database
CRUD operations. To run these operations, call ``QuerySet`` methods
on your model's ``Manager`` instance? object?. The ``Manager`` class handles database

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aclark4life you suggested I remove "instance" - is it more accurate to replace with "object" or just keep as is?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like Manager object.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manager is a class with QuerySet methods mixed in: https://github.com/django/django/blob/stable/5.1.x/django/db/models/manager.py#L176.

The default Manager is called objects … and it's an attribute of the model class… but yeah, looking at Django's documentation a manager typically referred to as just "manager". It may help to use "manager" instead of Manager since we're referring to the model's manager and not the Manager class e.g.: https://docs.djangoproject.com/en/5.1/topics/db/queries/#retrieving-objects

Lastly, I find instance and object confusing for various reasons. I would say if you see Django using those terms go for it, else stick close to how Django describers managers as much as possible.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correcting myself: this is how Django says it:

"To retrieve objects from your database, construct a QuerySet via a Manager on your model class."

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay thank you! I will use "model's manager" as much as possible

operations and allows you to interact with your MongoDB data by referencing
Django models. By default, Django adds a ``Manager`` named ``objects``
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

S: consider making just "Django" a source constant as its a word with a high possibility of typos, IMO

to every model class.

This guide shows how to use the following ``QuerySet`` methods:

- :ref:`create() <django-crud-insert>`
- :ref:`filter() and get() <django-crud-read>`
- :ref:`update() <django-crud-modify>`
- :ref:`delete() <django-crud-delete>`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- :ref:`create() <django-crud-insert>`
- :ref:`filter() and get() <django-crud-read>`
- :ref:`update() <django-crud-modify>`
- :ref:`delete() <django-crud-delete>`
- :ref:`create() <django-crud-insert>`: Insert new data
- :ref:`filter() and get() <django-crud-read>`: Retrieve specific documents... etc
- :ref:`update() <django-crud-modify>`
- :ref:`delete() <django-crud-delete>`


.. tip::

To learn more about Django's ``QuerySet`` API, see
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
To learn more about Django's ``QuerySet`` API, see
To learn more about Django's ``QuerySet`` API, see the

`QuerySet API reference <https://docs.djangoproject.com/en/5.1/ref/models/querysets/>`__

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using intersphinx for linking to Django docs? The objects file: http://docs.djangoproject.com/en/5.0/_objects/ I think this would be especially helpful for making sure links stay updated when switching from one Django version to the next.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there is some precedent for that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking into this!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@norareidy were we able to get resolve the issue with sphinx?

in the Django documentation.

You can also use the Django admin site to edit your models
and their corresponding collections on a web interface. For
more information, see `The Django admin site <https://docs.djangoproject.com/en/5.1/ref/contrib/admin/>`__
in the Django documentation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

S: to get around how weird the capitalization looks here

Suggested change
more information, see `The Django admin site <https://docs.djangoproject.com/en/5.1/ref/contrib/admin/>`__
in the Django documentation.
more information, see the `Django Admin Site <https://docs.djangoproject.com/en/5.1/ref/contrib/admin/>`__
entry in the Django documentation.


Sample Data
~~~~~~~~~~~

The examples in this guide use the ``Movie`` model, which represents
the ``sample_mflix.movies`` collection from the :atlas:`Atlas sample datasets </sample-data>`.
The ``Movie`` model class has the following definition:

.. code-block:: python

from django.db import models
from django_mongodb_backend.fields import EmbeddedModelField, ArrayField

class Movie(models.Model):
title = models.CharField(max_length=200)
plot = models.TextField(blank=True)
runtime = models.IntegerField(default=0)
released = models.DateTimeField("release date", null=True, blank=True)
awards = EmbeddedModelField(Award)
genres = ArrayField(models.CharField(max_length=100), null=True, blank=True)

class Meta:
db_table = "movies"
managed = False
Comment on lines +71 to +73
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a helpful tooltip or note to explain the purpose of these two meta configurations. A blurb along the lines of:
"""
In Django, defining a Meta class within a Model allows you to configure the Meta options for the model. In this example, we use db_table = "movies" to change the collection referenced in the database to look for movies, and we set managed = False to stop database creation, modification, or deletion during migration commands. To read more, check out Django's Meta Options documentation.
"""

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I use this sample data on almost every page, what do you think of linking to the Models guide (which explains Meta and str()) instead of repeating the explanation every time?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me


def __str__(self):
return self.title
Comment on lines +75 to +76
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Another helpful tooltip:
"""
In Django, you can override the str method of a model to define how its instances are represented as strings.
"""

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Works for me


You can use the Python interactive shell to run the code examples.
To enter the shell, run the following command from your project's
root directory:

.. code-block:: bash

python manage.py shell

After entering the Python shell, ensure that you import the following models and
modules:

.. code-block:: python

from <your application name>.models import Movie
from django.utils import timezone
from datetime import datetime

To learn how to create a Django application that uses the ``Movie``
model and the Python interactive shell to interact with MongoDB documents,
visit the :ref:`django-get-started` tutorial.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: link broken until #132 is merged


.. _django-crud-insert:

Insert Documents
----------------

To insert a document into a collection, call the ``create()`` method on your
model's ``Manager`` class. Pass the new document's field names and field values
as arguments to the ``create()`` method.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To insert a document into a collection, call the create() method on your model's Manager class. Pass the new document's field names and field values as arguments to the create() method.

Example
~~~~~~~

The following example calls the ``create()`` method to insert a document
into the ``sample_mflix.movies`` collection. The new document has
a ``title`` value of ``"Poor Things"`` and a ``runtime`` value
of ``141``:

.. code-block:: python

movie = Movie.objects.create(title="Poor Things", runtime=141)

.. note::

The ``create()`` method allows you to create a new ``Movie`` object
and save the object as a collection document in one method call.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The ``create()`` method allows you to create a new ``Movie`` object
and save the object as a collection document in one method call.
The ``create()`` method allows you to create a new ``Movie`` object
and save the object to MongoDB in one method call.

To view an example that creates an object then saves it to the
database by calling ``save()``, see `create() <https://docs.djangoproject.com/en/5.1/ref/models/querysets/#create>`__
in the Django documentation.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if you want to mention this shortcut here, but I think you can also do this:

movie = Movie(title="Poor Things", runtime=141)

Presumably this works because instantiation of the class calls the manager's create method or something like that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you still need to call save() after to actually insert it into the database

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: why not include this example here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added


.. _django-crud-read:

Read Documents
--------------

To retrieve documents from your collection, call the ``filter()`` method
on your model's ``Manager`` class. Pass a query filter, or criteria
that specifies which documents to retrieve, as an argument to the ``filter()`` method.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To retrieve documents from your collection, call the filter() method on your model's Manager class.


Alternatively, you can call the ``get()`` method to retrieve a single document
that matches your query.

Return Multiple Documents Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The following example calls the ``filter()`` method to retrieve
documents from the ``sample_mflix.movies`` collection. The query
returns ``Movie`` objects that represent movies released on January 1, 2000:

.. io-code-block::
:copyable: true

.. input::
:language: python

Movie.objects.filter(released=timezone.make_aware(datetime(2000, 1, 1)))

.. output::
:language: none
:visible: false

<QuerySet [<Movie: The Bumblebee Flies Anyway>, <Movie: Angels of the Universe>,
<Movie: First Person Plural>, <Movie: Just, Melvin: Just Evil>, <Movie: Sound and Fury>,
<Movie: Peppermint Candy>]>

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking we should add a tooltip to link to the lookup operations documentation in Django.

cc: @aclark4life @timgraham

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean add a link to the Django documentation for each method at the end of the sections? I can do that!

Return One Document Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To retrieve only one document that matches your query criteria, call the
``get()`` method and pass a query filter as an argument. The following example
retrieves a document in which the ``title`` value is ``"Boyhood"``:

.. io-code-block::
:copyable: true

.. input::
:language: python

Movie.objects.get(title="Boyhood")

.. output::
:language: none
:visible: false

<Movie: Boyhood>

.. important::

If your query matches no documents or multiple documents, the ``get()``
method generates an error. To retrieve one document from a query
that might match multiple, chain the ``first()`` method to ``filter()``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

S: you can still link to the specify a query guide in the TODO, but adding a one line example here of chaining first() wouldnt be a bad idea either!


.. TODO: To view an example that uses the ``first()`` method, see
:ref:`` in the Specify a Query guide.

.. _django-crud-modify:

Modify Documents
----------------

To modify documents in a collection, call the ``filter()`` and ``update()``
methods on your model's ``Manager`` class. Pass a query filter,
or criteria that specifies which documents to update, as an argument to the
``filter()`` method. Then, pass the fields and values you want to update as
arguments to the ``update()`` method.

Example
~~~~~~~

The following example calls the ``update()`` method to modify
documents in the ``sample_mflix.movies`` collection. The code matches
a document that has a ``title`` value of ``"High Fidelity"`` and adds a
``plot`` field:

.. io-code-block::
:copyable: true

.. input::
:language: python

Movie.objects.filter(title="High Fidelity").update(plot=
"Rob, a record store owner and compulsive list maker, recounts his top five breakups, including the one in progress.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: fix indentation?


.. output::
:language: none
:visible: false

// Outputs the number of modified documents
1

.. _django-crud-delete:

Delete Documents
----------------

To delete documents in a collection, call the ``filter()`` and ``delete()``
methods on your model's ``Manager`` class. Pass a query filter,
or criteria that specifies which documents to delete, as an argument to the
``filter()`` method.

Example
~~~~~~~

The following example calls the ``delete()`` method to delete documents
in the ``sample_mflix.movies`` collection. The code matches
and deletes documents that have a ``runtime`` value of ``5``:

.. io-code-block::
:copyable: true

.. input::
:language: python

Movie.objects.filter(runtime=5).delete()

.. output::
:language: none
:visible: false

// Outputs the number of deleted documents and objects
(16, {'sample_mflix.Movie': 16})


Additional Information
----------------------

.. TODO: To learn more about performing read operations, see the Specify a Query guide.

To view more create, read, update, and delete examples, see the following
steps of the :ref:`django-get-started` tutorial:

- :ref:`django-get-started-write`
- :ref:`django-get-started-query`
Loading