.. index:: Manager, Models, Object Relational Mapper, ORM ***************** Create the Models ***************** "A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table." -- :djangodocs:`Models | Django documentation ` The next step is to create the data structure with help from models. Models define how data is saved. Usually a model represents a table in the database, and has fields, metadata and methods. With this information Django can automatically generate an interface to the database that allows object oriented access to it. This is called Object-Relation-Mapping (ORM). .. graphviz:: models.dot :alt: An entity–relationship model of our application :inline: .. raw:: latex \newpage In django-marcador, two models are required. You can see them in the entity–relationship model above. ``Bookmark`` represents the actual bookmarks and has fields for URL, title and description. Data about who created the bookmark and when, as well as whether the bookmark is public or not is also stored here. This data will be used later to filter the bookmarks. A second model ``Tag`` represents keywords that can be attached to bookmarks to make them easier to find. ``Bookmark`` and ``Tag`` have a many-to-many relationship, so Django will create the intermediate table automatically. In order that Django recognises your class as a model, it must inherit from ``django.db.models.Model`` and be placed in :file:`models.py` in your app directory (in this example :file:`mysite/marcador/`). .. _model-fields: Fields ====== Fields are defined as class attributes, and map to the columns in the table. Django has several different types of fields, in order to allow access to the data in the most sensible way. For example ``CharField`` means a ``VARCHAR`` column in an SQL database. You can find a :djangodocs:`list of field types ` in the Django documentation. .. literalinclude:: ../src/mysite/marcador/models.py :lines: 1-3, 6-7, 9-10, 25-26, 28-37 :linenos: Metadata ======== Models can contain :djangodocs:`Metadata `, that can influence how they are displayed or how they behave. They are defined in the internal class ``Meta``. In the example, the display name for presentation is set (singular and plural), as well as the default sort order. .. literalinclude:: ../src/mysite/marcador/models.py :lines: 1-3, 6-7, 9-15, 25-26, 28-37, 41-45 :emphasize-lines: 9-12, 26-29 :linenos: .. _model-methods: Methods ======= You can now add Model functionality :djangodocs:`Methods ` for actions that apply to a single record. For instance, it is usual to create a human readable form of the record with the method ``__str__``. .. literalinclude:: ../src/mysite/marcador/models.py :lines: 1-18, 25-37, 41-54 :emphasize-lines: 4-5, 8, 17-18, 21, 38-45 :linenos: In the bookmark model, we'll also override the method ``save()`` to set the right creation or last-changed date. The state of the ``id`` field will be used, in order to decide if the model has already been saved or not. The field ``id`` exists in every model - if it's not explicitely declared, Django will create it automatically. It is used as the primary key of the model, to uniquely identify the record. If this field doesn't exist, the model hasn't been saved yet. As a last step, the function ``super()`` is used to call the method ``save()`` from the base class (i.e. the class that we've inherited from). .. note:: Marcador supports Python 2 and Python 3. This is achieved by the the decorator ``@python_2_unicode_compatible`` and by using ``__str__`` instead of ``__unicode__`` as you may find it in older versions of the documentation. .. _manager: Manager ======= In order to run the database queries, there's a :djangodocs:`manager ` for every model. Unless it's otherwise defined, the attribute ``objects`` holds a reference to the default manager. The queries can be altered by overriding the default manager or adding another one. The Django documentation explains the usage of a manager as follows: "To retrieve objects from your database, construct a ``QuerySet`` via a ``Manager`` on your model class. A ``QuerySet`` represents a collection of objects from your database. It can have zero, one or many *filters* -- criteria that narrow down the collection based on given parameters. In SQL terms, a ``QuerySet`` equates to a ``SELECT`` statement, and a filter is a limiting clause such as ``WHERE`` or ``LIMIT``." -- :djangodocs:`Making queries | Django documentation ` Most of the ``QuerySet`` methods return a new ``QuerySet`` so you can combine multiple of them. To access the items in a ``QuerySet`` you can loop over it or simply use the item's index. For example the following Python code returns the first item of a ``QuerySet`` which contains all public bookmarks ordered by their title: :: >>> Bookmark.objects.filter(is_public=True).order_by('title')[0] The SQL query executed against the database for the Python code above looks like this: .. code-block:: sql SELECT "marcador_bookmark"."id", "marcador_bookmark"."url", "marcador_bookmark"."title", "marcador_bookmark"."description", "marcador_bookmark"."is_public", "marcador_bookmark"."date_created", "marcador_bookmark"."date_updated", "marcador_bookmark"."owner_id" FROM "marcador_bookmark" WHERE "marcador_bookmark"."is_public" = True ORDER BY "marcador_bookmark"."title" ASC LIMIT 1 You can find a list of all ``QuerySet`` methods in the :djangodocs:`documentation `. In our example we'll often show only public bookmarks so we add a second manager to the ``Bookmark`` model that will only return the public bookmarks. We'll assign it to the attribute ``public``. In order to keep a reference to the default manager, we have to explicitely assign it to the ``objects`` attribute of the ``Bookmark`` class. .. literalinclude:: ../src/mysite/marcador/models.py :lines: 21-54 :emphasize-lines: 1-4, 19-20 :linenos: The complete file ================= When everything is complete, the file :file:`models.py` should look as follows: .. literalinclude:: ../src/mysite/marcador/models.py :linenos: