| ===================================== |
| Writing your first Django app, part 1 |
| ===================================== |
| |
| Let's learn by example. |
| |
| Throughout this tutorial, we'll walk you through the creation of a basic |
| poll application. |
| |
| It'll consist of two parts: |
| |
| * A public site that lets people view polls and vote in them. |
| * An admin site that lets you add, change and delete polls. |
| |
| We'll assume you have :doc:`Django installed </intro/install>` already. You can |
| tell Django is installed and which version by running the following command: |
| |
| .. code-block:: bash |
| |
| python -c "import django; print(django.get_version())" |
| |
| If Django is installed, you should see the version of your installation. If it |
| isn't, you'll get an error telling "No module named django". |
| |
| This tutorial is written for Django |version| and Python 2.x. If the Django |
| version doesn't match, you can refer to the tutorial for your version of Django |
| or update Django to the newest version. If you are using Python 3.x, be aware |
| that your code may need to differ from what is in the tutorial and you should |
| continue using the tutorial only if you know what you are doing with Python |
| 3.x. |
| |
| See :doc:`How to install Django </topics/install>` for advice on how to remove |
| older versions of Django and install a newer one. |
| |
| .. admonition:: Where to get help: |
| |
| If you're having trouble going through this tutorial, please post a message |
| to `django-users`__ or drop by `#django on irc.freenode.net`__ to chat |
| with other Django users who might be able to help. |
| |
| __ http://groups.google.com/group/django-users |
| __ irc://irc.freenode.net/django |
| |
| Creating a project |
| ================== |
| |
| If this is your first time using Django, you'll have to take care of some |
| initial setup. Namely, you'll need to auto-generate some code that establishes a |
| Django :term:`project` -- a collection of settings for an instance of Django, |
| including database configuration, Django-specific options and |
| application-specific settings. |
| |
| From the command line, ``cd`` into a directory where you'd like to store your |
| code, then run the following command: |
| |
| .. code-block:: bash |
| |
| django-admin.py startproject mysite |
| |
| This will create a ``mysite`` directory in your current directory. If it didn't |
| work, see :ref:`troubleshooting-django-admin-py`. |
| |
| .. note:: |
| |
| You'll need to avoid naming projects after built-in Python or Django |
| components. In particular, this means you should avoid using names like |
| ``django`` (which will conflict with Django itself) or ``test`` (which |
| conflicts with a built-in Python package). |
| |
| .. admonition:: Where should this code live? |
| |
| If your background is in plain old PHP (with no use of modern frameworks), |
| you're probably used to putting code under the Web server's document root |
| (in a place such as ``/var/www``). With Django, you don't do that. It's |
| not a good idea to put any of this Python code within your Web server's |
| document root, because it risks the possibility that people may be able |
| to view your code over the Web. That's not good for security. |
| |
| Put your code in some directory **outside** of the document root, such as |
| :file:`/home/mycode`. |
| |
| Let's look at what :djadmin:`startproject` created:: |
| |
| mysite/ |
| manage.py |
| mysite/ |
| __init__.py |
| settings.py |
| urls.py |
| wsgi.py |
| |
| .. admonition:: Doesn't match what you see? |
| |
| The default project layout recently changed. If you're seeing a "flat" |
| layout (with no inner :file:`mysite/` directory), you're probably using |
| a version of Django that doesn't match this tutorial version. You'll |
| want to either switch to the older tutorial or the newer Django version. |
| |
| These files are: |
| |
| * The outer :file:`mysite/` root directory is just a container for your |
| project. Its name doesn't matter to Django; you can rename it to anything |
| you like. |
| |
| * :file:`manage.py`: A command-line utility that lets you interact with this |
| Django project in various ways. You can read all the details about |
| :file:`manage.py` in :doc:`/ref/django-admin`. |
| |
| * The inner :file:`mysite/` directory is the actual Python package for your |
| project. Its name is the Python package name you'll need to use to import |
| anything inside it (e.g. ``mysite.urls``). |
| |
| * :file:`mysite/__init__.py`: An empty file that tells Python that this |
| directory should be considered a Python package. (Read `more about |
| packages`_ in the official Python docs if you're a Python beginner.) |
| |
| * :file:`mysite/settings.py`: Settings/configuration for this Django |
| project. :doc:`/topics/settings` will tell you all about how settings |
| work. |
| |
| * :file:`mysite/urls.py`: The URL declarations for this Django project; a |
| "table of contents" of your Django-powered site. You can read more about |
| URLs in :doc:`/topics/http/urls`. |
| |
| * :file:`mysite/wsgi.py`: An entry-point for WSGI-compatible webservers to |
| serve your project. See :doc:`/howto/deployment/wsgi/index` for more details. |
| |
| .. _more about packages: http://docs.python.org/tutorial/modules.html#packages |
| |
| The development server |
| ---------------------- |
| |
| Let's verify this worked. Change into the outer :file:`mysite` directory, if |
| you haven't already, and run the command ``python manage.py runserver``. You'll |
| see the following output on the command line: |
| |
| .. parsed-literal:: |
| |
| Validating models... |
| |
| 0 errors found |
| |today| - 15:50:53 |
| Django version |version|, using settings 'mysite.settings' |
| Development server is running at http://127.0.0.1:8000/ |
| Quit the server with CONTROL-C. |
| |
| You've started the Django development server, a lightweight Web server written |
| purely in Python. We've included this with Django so you can develop things |
| rapidly, without having to deal with configuring a production server -- such as |
| Apache -- until you're ready for production. |
| |
| Now's a good time to note: **Don't** use this server in anything resembling a |
| production environment. It's intended only for use while developing. (We're in |
| the business of making Web frameworks, not Web servers.) |
| |
| Now that the server's running, visit http://127.0.0.1:8000/ with your Web |
| browser. You'll see a "Welcome to Django" page, in pleasant, light-blue pastel. |
| It worked! |
| |
| .. admonition:: Changing the port |
| |
| By default, the :djadmin:`runserver` command starts the development server |
| on the internal IP at port 8000. |
| |
| If you want to change the server's port, pass |
| it as a command-line argument. For instance, this command starts the server |
| on port 8080: |
| |
| .. code-block:: bash |
| |
| python manage.py runserver 8080 |
| |
| If you want to change the server's IP, pass it along with the port. So to |
| listen on all public IPs (useful if you want to show off your work on other |
| computers), use: |
| |
| .. code-block:: bash |
| |
| python manage.py runserver 0.0.0.0:8000 |
| |
| Full docs for the development server can be found in the |
| :djadmin:`runserver` reference. |
| |
| .. admonition:: Automatic reloading of :djadmin:`runserver` |
| |
| The development server automatically reloads Python code for each request |
| as needed. You don't need to restart the server for code changes to take |
| effect. However, some actions like adding files or compiling translation |
| files don't trigger a restart, so you'll have to restart the server in |
| these cases. |
| |
| Database setup |
| -------------- |
| |
| Now, edit :file:`mysite/settings.py`. It's a normal Python module with |
| module-level variables representing Django settings. Change the |
| following keys in the :setting:`DATABASES` ``'default'`` item to match |
| your database connection settings. |
| |
| * :setting:`ENGINE <DATABASE-ENGINE>` -- Either |
| ``'django.db.backends.postgresql_psycopg2'``, |
| ``'django.db.backends.mysql'``, ``'django.db.backends.sqlite3'`` or |
| ``'django.db.backends.oracle'``. Other backends are :setting:`also available |
| <DATABASE-ENGINE>`. |
| |
| * :setting:`NAME` -- The name of your database. If you're using |
| SQLite, the database will be a file on your computer; in that |
| case, :setting:`NAME` should be the full absolute path, |
| including filename, of that file. If the file doesn't exist, it |
| will automatically be created when you synchronize the database |
| for the first time (see below). |
| |
| When specifying the path, always use forward slashes, even on |
| Windows (e.g. ``C:/homes/user/mysite/sqlite3.db``). |
| |
| * :setting:`USER` -- Your database username (not used for SQLite). |
| |
| * :setting:`PASSWORD` -- Your database password (not used for |
| SQLite). |
| |
| * :setting:`HOST` -- The host your database is on. Leave this as |
| an empty string (or possibly ``127.0.0.1``) if your database server is on the |
| same physical machine (not used for SQLite). See :setting:`HOST` for details. |
| |
| If you're new to databases, we recommend simply using SQLite by setting |
| :setting:`ENGINE <DATABASE-ENGINE>` to ``'django.db.backends.sqlite3'`` and |
| :setting:`NAME` to the place where you'd like to store the database. SQLite is |
| included in Python, so you won't need to install anything else to support your |
| database. |
| |
| .. note:: |
| |
| If you're using PostgreSQL or MySQL, make sure you've created a database by |
| this point. Do that with "``CREATE DATABASE database_name;``" within your |
| database's interactive prompt. |
| |
| If you're using SQLite, you don't need to create anything beforehand - the |
| database file will be created automatically when it is needed. |
| |
| While you're editing :file:`settings.py`, set :setting:`TIME_ZONE` to your |
| time zone. The default value is the Central time zone in the U.S. (Chicago). |
| |
| Also, note the :setting:`INSTALLED_APPS` setting toward the bottom of |
| the file. That holds the names of all Django applications that are |
| activated in this Django instance. Apps can be used in multiple projects, and |
| you can package and distribute them for use by others in their projects. |
| |
| By default, :setting:`INSTALLED_APPS` contains the following apps, all of which |
| come with Django: |
| |
| * :mod:`django.contrib.auth` -- An authentication system. |
| |
| * :mod:`django.contrib.contenttypes` -- A framework for content types. |
| |
| * :mod:`django.contrib.sessions` -- A session framework. |
| |
| * :mod:`django.contrib.sites` -- A framework for managing multiple sites |
| with one Django installation. |
| |
| * :mod:`django.contrib.messages` -- A messaging framework. |
| |
| * :mod:`django.contrib.staticfiles` -- A framework for managing |
| static files. |
| |
| These applications are included by default as a convenience for the common case. |
| |
| Each of these applications makes use of at least one database table, though, |
| so we need to create the tables in the database before we can use them. To do |
| that, run the following command: |
| |
| .. code-block:: bash |
| |
| python manage.py syncdb |
| |
| The :djadmin:`syncdb` command looks at the :setting:`INSTALLED_APPS` setting |
| and creates any necessary database tables according to the database settings |
| in your :file:`mysite/settings.py` file. You'll see a message for each |
| database table it creates, and you'll get a prompt asking you if you'd like to |
| create a superuser account for the authentication system. Go ahead and do |
| that. |
| |
| If you're interested, run the command-line client for your database and type |
| ``\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to |
| display the tables Django created. |
| |
| .. admonition:: For the minimalists |
| |
| Like we said above, the default applications are included for the common |
| case, but not everybody needs them. If you don't need any or all of them, |
| feel free to comment-out or delete the appropriate line(s) from |
| :setting:`INSTALLED_APPS` before running :djadmin:`syncdb`. The |
| :djadmin:`syncdb` command will only create tables for apps in |
| :setting:`INSTALLED_APPS`. |
| |
| .. _creating-models: |
| |
| Creating models |
| =============== |
| |
| Now that your environment -- a "project" -- is set up, you're set to start |
| doing work. |
| |
| Each application you write in Django consists of a Python package, somewhere |
| on your `Python path`_, that follows a certain convention. Django comes with a |
| utility that automatically generates the basic directory structure of an app, |
| so you can focus on writing code rather than creating directories. |
| |
| .. admonition:: Projects vs. apps |
| |
| What's the difference between a project and an app? An app is a Web |
| application that does something -- e.g., a Weblog system, a database of |
| public records or a simple poll app. A project is a collection of |
| configuration and apps for a particular Web site. A project can contain |
| multiple apps. An app can be in multiple projects. |
| |
| Your apps can live anywhere on your `Python path`_. In this tutorial, we'll |
| create our poll app right next to your :file:`manage.py` file so that it can be |
| imported as its own top-level module, rather than a submodule of ``mysite``. |
| |
| To create your app, make sure you're in the same directory as :file:`manage.py` |
| and type this command: |
| |
| .. code-block:: bash |
| |
| python manage.py startapp polls |
| |
| That'll create a directory :file:`polls`, which is laid out like this:: |
| |
| polls/ |
| __init__.py |
| models.py |
| tests.py |
| views.py |
| |
| This directory structure will house the poll application. |
| |
| The first step in writing a database Web app in Django is to define your models |
| -- essentially, your database layout, with additional metadata. |
| |
| .. admonition:: Philosophy |
| |
| A model is the single, definitive source of data about your data. It contains |
| the essential fields and behaviors of the data you're storing. Django follows |
| the :ref:`DRY Principle <dry>`. The goal is to define your data model in one |
| place and automatically derive things from it. |
| |
| In our simple poll app, we'll create two models: ``Poll`` and ``Choice``. |
| A ``Poll`` has a question and a publication date. A ``Choice`` has two fields: |
| the text of the choice and a vote tally. Each ``Choice`` is associated with a |
| ``Poll``. |
| |
| These concepts are represented by simple Python classes. Edit the |
| :file:`polls/models.py` file so it looks like this:: |
| |
| from django.db import models |
| |
| class Poll(models.Model): |
| question = models.CharField(max_length=200) |
| pub_date = models.DateTimeField('date published') |
| |
| class Choice(models.Model): |
| poll = models.ForeignKey(Poll) |
| choice_text = models.CharField(max_length=200) |
| votes = models.IntegerField(default=0) |
| |
| The code is straightforward. Each model is represented by a class that |
| subclasses :class:`django.db.models.Model`. Each model has a number of class |
| variables, each of which represents a database field in the model. |
| |
| Each field is represented by an instance of a :class:`~django.db.models.Field` |
| class -- e.g., :class:`~django.db.models.CharField` for character fields and |
| :class:`~django.db.models.DateTimeField` for datetimes. This tells Django what |
| type of data each field holds. |
| |
| The name of each :class:`~django.db.models.Field` instance (e.g. ``question`` or |
| ``pub_date`` ) is the field's name, in machine-friendly format. You'll use this |
| value in your Python code, and your database will use it as the column name. |
| |
| You can use an optional first positional argument to a |
| :class:`~django.db.models.Field` to designate a human-readable name. That's used |
| in a couple of introspective parts of Django, and it doubles as documentation. |
| If this field isn't provided, Django will use the machine-readable name. In this |
| example, we've only defined a human-readable name for ``Poll.pub_date``. For all |
| other fields in this model, the field's machine-readable name will suffice as |
| its human-readable name. |
| |
| Some :class:`~django.db.models.Field` classes have required arguments. |
| :class:`~django.db.models.CharField`, for example, requires that you give it a |
| :attr:`~django.db.models.CharField.max_length`. That's used not only in the |
| database schema, but in validation, as we'll soon see. |
| |
| A :class:`~django.db.models.Field` can also have various optional arguments; in |
| this case, we've set the :attr:`~django.db.models.Field.default` value of |
| ``votes`` to 0. |
| |
| Finally, note a relationship is defined, using |
| :class:`~django.db.models.ForeignKey`. That tells Django each ``Choice`` is related |
| to a single ``Poll``. Django supports all the common database relationships: |
| many-to-ones, many-to-manys and one-to-ones. |
| |
| .. _`Python path`: http://docs.python.org/tutorial/modules.html#the-module-search-path |
| |
| Activating models |
| ================= |
| |
| That small bit of model code gives Django a lot of information. With it, Django |
| is able to: |
| |
| * Create a database schema (``CREATE TABLE`` statements) for this app. |
| * Create a Python database-access API for accessing ``Poll`` and ``Choice`` objects. |
| |
| But first we need to tell our project that the ``polls`` app is installed. |
| |
| .. admonition:: Philosophy |
| |
| Django apps are "pluggable": You can use an app in multiple projects, and |
| you can distribute apps, because they don't have to be tied to a given |
| Django installation. |
| |
| Edit the :file:`settings.py` file again, and change the |
| :setting:`INSTALLED_APPS` setting to include the string ``'polls'``. So |
| it'll look like this:: |
| |
| INSTALLED_APPS = ( |
| 'django.contrib.auth', |
| 'django.contrib.contenttypes', |
| 'django.contrib.sessions', |
| 'django.contrib.sites', |
| 'django.contrib.messages', |
| 'django.contrib.staticfiles', |
| # Uncomment the next line to enable the admin: |
| # 'django.contrib.admin', |
| # Uncomment the next line to enable admin documentation: |
| # 'django.contrib.admindocs', |
| 'polls', |
| ) |
| |
| Now Django knows to include the ``polls`` app. Let's run another |
| command: |
| |
| .. code-block:: bash |
| |
| python manage.py sql polls |
| |
| You should see something similar to the following (the ``CREATE TABLE`` SQL |
| statements for the polls app): |
| |
| .. code-block:: sql |
| |
| BEGIN; |
| CREATE TABLE "polls_poll" ( |
| "id" serial NOT NULL PRIMARY KEY, |
| "question" varchar(200) NOT NULL, |
| "pub_date" timestamp with time zone NOT NULL |
| ); |
| CREATE TABLE "polls_choice" ( |
| "id" serial NOT NULL PRIMARY KEY, |
| "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id") DEFERRABLE INITIALLY DEFERRED, |
| "choice_text" varchar(200) NOT NULL, |
| "votes" integer NOT NULL |
| ); |
| COMMIT; |
| |
| Note the following: |
| |
| * The exact output will vary depending on the database you are using. |
| |
| * Table names are automatically generated by combining the name of the app |
| (``polls``) and the lowercase name of the model -- ``poll`` and |
| ``choice``. (You can override this behavior.) |
| |
| * Primary keys (IDs) are added automatically. (You can override this, too.) |
| |
| * By convention, Django appends ``"_id"`` to the foreign key field name. |
| (Yes, you can override this, as well.) |
| |
| * The foreign key relationship is made explicit by a ``REFERENCES`` |
| statement. |
| |
| * It's tailored to the database you're using, so database-specific field |
| types such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or |
| ``integer primary key`` (SQLite) are handled for you automatically. Same |
| goes for quoting of field names -- e.g., using double quotes or single |
| quotes. The author of this tutorial runs PostgreSQL, so the example |
| output is in PostgreSQL syntax. |
| |
| * The :djadmin:`sql` command doesn't actually run the SQL in your database - |
| it just prints it to the screen so that you can see what SQL Django thinks |
| is required. If you wanted to, you could copy and paste this SQL into your |
| database prompt. However, as we will see shortly, Django provides an |
| easier way of committing the SQL to the database. |
| |
| If you're interested, also run the following commands: |
| |
| * :djadmin:`python manage.py validate <validate>` -- Checks for any errors |
| in the construction of your models. |
| |
| * :djadmin:`python manage.py sqlcustom polls <sqlcustom>` -- Outputs any |
| :ref:`custom SQL statements <initial-sql>` (such as table modifications or |
| constraints) that are defined for the application. |
| |
| * :djadmin:`python manage.py sqlclear polls <sqlclear>` -- Outputs the |
| necessary ``DROP TABLE`` statements for this app, according to which |
| tables already exist in your database (if any). |
| |
| * :djadmin:`python manage.py sqlindexes polls <sqlindexes>` -- Outputs the |
| ``CREATE INDEX`` statements for this app. |
| |
| * :djadmin:`python manage.py sqlall polls <sqlall>` -- A combination of all |
| the SQL from the :djadmin:`sql`, :djadmin:`sqlcustom`, and |
| :djadmin:`sqlindexes` commands. |
| |
| Looking at the output of those commands can help you understand what's actually |
| happening under the hood. |
| |
| Now, run :djadmin:`syncdb` again to create those model tables in your database: |
| |
| .. code-block:: bash |
| |
| python manage.py syncdb |
| |
| The :djadmin:`syncdb` command runs the SQL from :djadmin:`sqlall` on your |
| database for all apps in :setting:`INSTALLED_APPS` that don't already exist in |
| your database. This creates all the tables, initial data and indexes for any |
| apps you've added to your project since the last time you ran syncdb. |
| :djadmin:`syncdb` can be called as often as you like, and it will only ever |
| create the tables that don't exist. |
| |
| Read the :doc:`django-admin.py documentation </ref/django-admin>` for full |
| information on what the ``manage.py`` utility can do. |
| |
| Playing with the API |
| ==================== |
| |
| Now, let's hop into the interactive Python shell and play around with the free |
| API Django gives you. To invoke the Python shell, use this command: |
| |
| .. code-block:: bash |
| |
| python manage.py shell |
| |
| We're using this instead of simply typing "python", because :file:`manage.py` |
| sets the ``DJANGO_SETTINGS_MODULE`` environment variable, which gives Django |
| the Python import path to your :file:`mysite/settings.py` file. |
| |
| .. admonition:: Bypassing manage.py |
| |
| If you'd rather not use :file:`manage.py`, no problem. Just set the |
| ``DJANGO_SETTINGS_MODULE`` environment variable to ``mysite.settings`` and |
| run ``python`` from the same directory :file:`manage.py` is in (or ensure |
| that directory is on the Python path, so that ``import mysite`` works). |
| |
| For more information on all of this, see the :doc:`django-admin.py |
| documentation </ref/django-admin>`. |
| |
| Once you're in the shell, explore the :doc:`database API </topics/db/queries>`:: |
| |
| >>> from polls.models import Poll, Choice # Import the model classes we just wrote. |
| |
| # No polls are in the system yet. |
| >>> Poll.objects.all() |
| [] |
| |
| # Create a new Poll. |
| # Support for time zones is enabled in the default settings file, so |
| # Django expects a datetime with tzinfo for pub_date. Use timezone.now() |
| # instead of datetime.datetime.now() and it will do the right thing. |
| >>> from django.utils import timezone |
| >>> p = Poll(question="What's new?", pub_date=timezone.now()) |
| |
| # Save the object into the database. You have to call save() explicitly. |
| >>> p.save() |
| |
| # Now it has an ID. Note that this might say "1L" instead of "1", depending |
| # on which database you're using. That's no biggie; it just means your |
| # database backend prefers to return integers as Python long integer |
| # objects. |
| >>> p.id |
| 1 |
| |
| # Access database columns via Python attributes. |
| >>> p.question |
| "What's new?" |
| >>> p.pub_date |
| datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>) |
| |
| # Change values by changing the attributes, then calling save(). |
| >>> p.question = "What's up?" |
| >>> p.save() |
| |
| # objects.all() displays all the polls in the database. |
| >>> Poll.objects.all() |
| [<Poll: Poll object>] |
| |
| |
| Wait a minute. ``<Poll: Poll object>`` is, utterly, an unhelpful representation |
| of this object. Let's fix that by editing the polls model (in the |
| ``polls/models.py`` file) and adding a |
| :meth:`~django.db.models.Model.__unicode__` method to both ``Poll`` and |
| ``Choice``. On Python 3, simply replace ``__unicode__`` by ``__str__`` in the |
| following example:: |
| |
| class Poll(models.Model): |
| # ... |
| def __unicode__(self): # Python 3: def __str__(self): |
| return self.question |
| |
| class Choice(models.Model): |
| # ... |
| def __unicode__(self): # Python 3: def __str__(self): |
| return self.choice_text |
| |
| It's important to add :meth:`~django.db.models.Model.__unicode__` methods (or |
| :meth:`~django.db.models.Model.__str__` on Python 3) to your models, not only |
| for your own sanity when dealing with the interactive prompt, but also because |
| objects' representations are used throughout Django's automatically-generated |
| admin. |
| |
| .. admonition:: :meth:`~django.db.models.Model.__unicode__` or |
| :meth:`~django.db.models.Model.__str__`? |
| |
| On Python 3, things are simpler, just use |
| :meth:`~django.db.models.Model.__str__` and forget about |
| :meth:`~django.db.models.Model.__unicode__`. |
| |
| If you're familiar with Python 2, you might be in the habit of adding |
| :meth:`~django.db.models.Model.__str__` methods to your classes, not |
| :meth:`~django.db.models.Model.__unicode__` methods. We use |
| :meth:`~django.db.models.Model.__unicode__` here because Django models deal |
| with Unicode by default. All data stored in your database is converted to |
| Unicode when it's returned. |
| |
| Django models have a default :meth:`~django.db.models.Model.__str__` method |
| that calls :meth:`~django.db.models.Model.__unicode__` and converts the |
| result to a UTF-8 bytestring. This means that ``unicode(p)`` will return a |
| Unicode string, and ``str(p)`` will return a normal string, with characters |
| encoded as UTF-8. |
| |
| If all of this is gibberish to you, just remember to add |
| :meth:`~django.db.models.Model.__unicode__` methods to your models. With any |
| luck, things should Just Work for you. |
| |
| Note these are normal Python methods. Let's add a custom method, just for |
| demonstration:: |
| |
| import datetime |
| from django.utils import timezone |
| # ... |
| class Poll(models.Model): |
| # ... |
| def was_published_recently(self): |
| return self.pub_date >= timezone.now() - datetime.timedelta(days=1) |
| |
| Note the addition of ``import datetime`` and ``from django.utils import |
| timezone``, to reference Python's standard :mod:`datetime` module and Django's |
| time-zone-related utilities in :mod:`django.utils.timezone`, respectively. If |
| you aren't familiar with time zone handling in Python, you can learn more in |
| the :doc:`time zone support docs </topics/i18n/timezones>`. |
| |
| Save these changes and start a new Python interactive shell by running |
| ``python manage.py shell`` again:: |
| |
| >>> from polls.models import Poll, Choice |
| |
| # Make sure our __unicode__() addition worked. |
| >>> Poll.objects.all() |
| [<Poll: What's up?>] |
| |
| # Django provides a rich database lookup API that's entirely driven by |
| # keyword arguments. |
| >>> Poll.objects.filter(id=1) |
| [<Poll: What's up?>] |
| >>> Poll.objects.filter(question__startswith='What') |
| [<Poll: What's up?>] |
| |
| # Get the poll that was published this year. |
| >>> from django.utils import timezone |
| >>> current_year = timezone.now().year |
| >>> Poll.objects.get(pub_date__year=current_year) |
| <Poll: What's up?> |
| |
| # Request an ID that doesn't exist, this will raise an exception. |
| >>> Poll.objects.get(id=2) |
| Traceback (most recent call last): |
| ... |
| DoesNotExist: Poll matching query does not exist. Lookup parameters were {'id': 2} |
| |
| # Lookup by a primary key is the most common case, so Django provides a |
| # shortcut for primary-key exact lookups. |
| # The following is identical to Poll.objects.get(id=1). |
| >>> Poll.objects.get(pk=1) |
| <Poll: What's up?> |
| |
| # Make sure our custom method worked. |
| >>> p = Poll.objects.get(pk=1) |
| >>> p.was_published_recently() |
| True |
| |
| # Give the Poll a couple of Choices. The create call constructs a new |
| # Choice object, does the INSERT statement, adds the choice to the set |
| # of available choices and returns the new Choice object. Django creates |
| # a set to hold the "other side" of a ForeignKey relation |
| # (e.g. a poll's choices) which can be accessed via the API. |
| >>> p = Poll.objects.get(pk=1) |
| |
| # Display any choices from the related object set -- none so far. |
| >>> p.choice_set.all() |
| [] |
| |
| # Create three choices. |
| >>> p.choice_set.create(choice_text='Not much', votes=0) |
| <Choice: Not much> |
| >>> p.choice_set.create(choice_text='The sky', votes=0) |
| <Choice: The sky> |
| >>> c = p.choice_set.create(choice_text='Just hacking again', votes=0) |
| |
| # Choice objects have API access to their related Poll objects. |
| >>> c.poll |
| <Poll: What's up?> |
| |
| # And vice versa: Poll objects get access to Choice objects. |
| >>> p.choice_set.all() |
| [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] |
| >>> p.choice_set.count() |
| 3 |
| |
| # The API automatically follows relationships as far as you need. |
| # Use double underscores to separate relationships. |
| # This works as many levels deep as you want; there's no limit. |
| # Find all Choices for any poll whose pub_date is in this year |
| # (reusing the 'current_year' variable we created above). |
| >>> Choice.objects.filter(poll__pub_date__year=current_year) |
| [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] |
| |
| # Let's delete one of the choices. Use delete() for that. |
| >>> c = p.choice_set.filter(choice_text__startswith='Just hacking') |
| >>> c.delete() |
| |
| For more information on model relations, see :doc:`Accessing related objects |
| </ref/models/relations>`. For more on how to use double underscores to perform |
| field lookups via the API, see :ref:`Field lookups <field-lookups-intro>`. For |
| full details on the database API, see our :doc:`Database API reference |
| </topics/db/queries>`. |
| |
| When you're comfortable with the API, read :doc:`part 2 of this tutorial |
| </intro/tutorial02>` to get Django's automatic admin working. |