Let's assume these concepts, fields and relationships below:
- An author has a last name, first name and email address.
- The publisher has a name, address, city, province, country, and website.
- A book has a title and a publication date. It has one or more authors (a many-to-many association [many-to-many] with the author(s)), and only one publisher (a one-to-many association [one-to-many] with the publisher, also known as a foreign key])
The first step is to describe them in Python code. Open the created by the ``startapp`` command and enter the following:
from import models class Publisher(): name = (max_length=30) address = (max_length=50) city = (max_length=60) state_province = (max_length=30) country = (max_length=50) website = () class Author(): first_name = (max_length=30) last_name = (max_length=40) email = () class Book(): title = (max_length=100) authors = (Author) publisher = (Publisher) publication_date = ()
Let's quickly explain what all this code means. The first thing to note is that every data model is a subclass of. Its parent class, Model, contains all the necessary methods for interacting with the database and provides a nice, clean syntax for defining database fields. Believe it or not, this is all the code we need to write to access basic data through Django.
Each model is equivalent to a single database table, and each attribute is a field in that table. The property name is the field name, and its type (e.g., CharField) is equivalent to the database field type (e.g., varchar). For example, the Publisher module is equivalent to the following table (described in PostgreSQL's CREATE TABLE syntax):
CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL );
In fact, as we'll show in a moment, Django can automatically generate these CREATE TABLE statements.
The exception to the "one class per database table" rule is many-to-many relationships. In our example model, Book has a many-to-many field called authors. This field indicates that a book has one or more authors, but the Book database table does not have an authors field. Instead, Django creates an additional table (a many-to-many join table) to handle the mapping between books and authors.
See Appendix B for all field type and model syntax options.
One final thing to note is that we are not explicitly defining any primary keys for these models. Django automatically generates a self-growing integer primary key field for each model unless you specify it separately Each Django model requires a separate primary key.
Model Installation
With that code done, let's now create these tables in the database. The first step in accomplishing this is to activate these models in your Django project. This is accomplished by adding the books app to the list of installed apps in the configuration file.
Edit the file again and find the INSTALLED_APPS setting. INSTALLED_APPS tells the Django project which apps are active. By default, it looks like this:
INSTALLED_APPS = ( '', '', '', '', )
Temporarily comment out these four settings by putting # in front of them. (These four apps are used frequently, and we'll discuss how to use them in subsequent sections.) Also, comment out the default settings entries for MIDDLEWARE_CLASSES, as these are dependent on the apps we just commented out in INSTALLED_APPS. Then, add `` '''``'' to the end of `` INSTALLED_APPS``, at which point the settings should look like It should look something like this:
MIDDLEWARE_CLASSES = ( # '', # '', # '', ) INSTALLED_APPS = ( # '', # '', # '', # '', '', )
(Just like the comma we mentioned in the previous chapter on setting TEMPLATE_DIRS, a comma also needs to be added at the end of INSTALLED_APPS, since this is a single-element tuple. Also, the authors of this book like to put a comma after every tuple element, regardless of whether it is only one element. This is to avoid forgetting to add commas, and it doesn't hurt.)
'' indicates the books app we are writing. Each app in INSTALLED_APPS is described using Python's path description for the package, with the decimal point "." spacing.
Now we can create the database tables. First, verify the validity of the model with the following command:
python validate
The validate command checks that the syntax and logic of your model is correct. If everything is fine, you will see the message 0 errors found. If there is an error, check the model code you entered. The error output will give you very useful error messages to help you correct your model.
Once you think there might be a problem with your model, run python validate . It can help you catch some common model definition errors.
With the model confirmed to be OK, run the following command to generate the CREATE TABLE statement (enable syntax highlighting if you are using Unix):
python sqlall books
In this command line, books is the name of the app. It's the same as if you were running startapp. After execution, the output looks like this:
BEGIN; CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL ) ; CREATE TABLE "books_author" ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(40) NOT NULL, "email" varchar(75) NOT NULL ) ; CREATE TABLE "books_book" ( "id" serial NOT NULL PRIMARY KEY, "title" varchar(100) NOT NULL, "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id") DEFERRABLE INITIALLY DEFERRED, "publication_date" date NOT NULL ) ; CREATE TABLE "books_book_authors" ( "id" serial NOT NULL PRIMARY KEY, "book_id" integer NOT NULL REFERENCES "books_book" ("id") DEFERRABLE INITIALLY DEFERRED, "author_id" integer NOT NULL REFERENCES "books_author" ("id") DEFERRABLE INITIALLY DEFERRED, UNIQUE ("book_id", "author_id") ) ; CREATE INDEX "books_book_publisher_id" ON "books_book" ("publisher_id"); COMMIT;
Attention:
- The automatically generated table name is a combination of the app name (books) and the lowercase name of the model (publisher , book , author ). You can refer to Appendix B to rewrite this rule.
- As we mentioned earlier, Django automatically adds an id primary key to each table, which you can reset.
- As promised, Django adds the "_id" suffix to the foreign key field name. You guessed it, this again is customizable.
- Foreign keys are explicitly defined with the REFERENCES statement.
- These CREATE TABLE statements are adapted to your database so that database-specific fields such as: (MySQL), auto_increment (PostgreSQL), serial (SQLite), are automatically generated. integer primary key Similarly, field names are automatically processed (e.g., single quotes or double quotes). handled (e.g., single quotes are okay for double quotes). The output in the example is based on PostgreSQL syntax.
The sqlall command doesn't actually create tables in the database, it just prints out the SQL statement segments so you can see what Django will actually do. If you wanted to do that, you could copy those SQL statements to your database client for execution, or you could do it directly through a Unix pipe (e.g., ``python sqlall books | psql mydb``). However, Django provides an easier way to commit SQL statements to the database: the `` syncdb`` command.
python syncdb
After executing this command,will see something similar to the following:
Creating table books_publisher Creating table books_author Creating table books_book Installing index for model
The syncdb command is a simple way to synchronize your model to a database. It checks the database against the app set in INSTALLED_APPS, and if the table does not exist, it creates it. Note that syncdb does not synchronize model modifications or deletions to the database; if you modify or delete a model and want to commit it to the database, syncdb will not do anything about it. (See the paragraph "Modifying the Database Architecture" at the end of this chapter for more information.)
If you run python syncdb again, nothing happens because you didn't add a new model or add a new app. so it's always safe to run python syncdb because it doesn't repeat the SQL statement.
If you're interested, take a moment to log into the database server with your SQL client to look at the data table that Django just created. You can start the command line client manually (for example, by executing the PostgreSQL ``psql`` command), or you can execute `` python dbshell``, which will automatically detect which command line client to use based on the `` DATABASE_SERVER`` settings. As they say, the later comes first.
Basic Data Access
Once you've created your models, Django automatically provides a high-level Python API for these models. Run a python shell and type the following to try it out:
>>> from import Publisher >>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue', ... city='Berkeley', state_province='CA', country='.', ... website='/') >>> () >>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.', ... city='Cambridge', state_province='MA', country='.', ... website='/') >>> () >>> publisher_list = () >>> publisher_list [<Publisher: Publisher object>, <Publisher: Publisher object>]
These few lines of code do quite a bit. Here's a brief rundown:
- First, import the Publisher model class, which allows us to interact with the table containing the publisher's data.
- Next, an instance of the ``Publisher`` class is created and the values of the fields ``name, address`` etc. are set.
- Call the object's save() method to save the object to the database. Django executes an INSERT statement in the background.
- Finally, the publisher information is retrieved from the database using the `` ` property, which can be thought of as a collection of records containing publishers. There are a number of methods for this property, and we'll start here by calling the `` ()`` method to get all the objects of the `` Publisher`` class in the database. Behind the scenes of this operation, Django executes an SQL `` SELECT`` statement.
Here's a noteworthy point that may not be clearly demonstrated in this example. When you create an object using the Django modle API Django does not save the object to the database unless you call the ``save()`` method:
p1 = Publisher(...) # At this point, p1 is not saved to the database yet! () # Now it is.
If you need to create an object and store it in the database in one step, use the `` ()`` method. The following example is equivalent to the previous one:
>>> p1 = (name='Apress', ... address='2855 Telegraph Avenue', ... city='Berkeley', state_province='CA', country='.', ... website='/') >>> p2 = (name="O'Reilly", ... address='10 Fawcett St.', city='Cambridge', ... state_province='MA', country='.', ... website='/') >>> publisher_list = () >>> publisher_list
Of course, you'll definitely want to implement more of the Django Database API to try it out, but let's fix a little annoying glitch first.
Add a string representation of the module
When we print the entire publisher list, we don't get the useful information we want to differentiate the ```` objects:
System Message: WARNING/2 (<string>, line 872); backlink Inline literal start-string without end-string. System Message: WARNING/2 (<string>, line 872); backlink Inline literal start-string without end-string. [<Publisher: Publisher object>, <Publisher: Publisher object>]
We can solve this problem simply by adding a method __unicode__() to the Publisher object. The __unicode__() method tells Python how to display the object as unicode. After adding the __unicode__() method to the above three models, you can see the results:
from import models class Publisher(): name = (max_length=30) address = (max_length=50) city = (max_length=60) state_province = (max_length=30) country = (max_length=50) website = () **def __unicode__(self):** **return ** class Author(): first_name = (max_length=30) last_name = (max_length=40) email = () **def __unicode__(self):** **return u'%s %s' % (self.first_name, self.last_name)** class Book(): title = (max_length=100) authors = (Author) publisher = (Publisher) publication_date = () **def __unicode__(self):** **return **
As you can see, the __unicode__() method can do anything to return a string representation of an object. The __unicode__() methods of the Publisher and Book objects simply return their respective names and titles, while the __unicode__() method of the Author object is slightly more complex, returning the first_name and last_name field values concatenated with spaces.
The only requirement for __unicode__() is that it return a unicode object If the `` __unicode__()`` method does not return a Unicode object, but instead returns, say, an integer number, then Python will throw a `` TypeError`` error with the message: "``coercing to Unicode: need string or buffer, int found''.