Django Learning Notes - First Application
The difference between Project and APP:
One is configuration, the other is code.
A project contains many Django app s and their configuration.
Technically, the role of project is to provide configuration files, such as where to define database connection information, list of installed app s, TEMPLATE_DIRS, etc.
An app is a set of Django functions, usually including models and views, which exist in python's package structure.
Django itself has some apps, eg: annotation system, automatic management interface. One of the key points of apps is that they can be easily ported to other projects and reused by multiple projects.
In general, there are no quick rules for how to structure Django code. If you're building a simple Web site, you probably only need an app; but if you're a complex site with many unrelated modules, such as e-commerce and community sites, you may need to divide these modules into different apps for later reuse.
Be careful:
The Django system has a convention for apps: if you use Django's database layer (model), you must create a Django app, and the model must be stored in apps.
Beginning with this example:
Enter the following command under the'mysite'project file to create'books' app:
python manage.py startapp books
Define the model in Python code:
M in MTV represents the model. Django model is the definition of data expressed in Python code in database. For the data layer, it is equivalent to a CREATE TABLE statement, except that it executes Python code instead of SQL, and contains more meanings than the definition of database fields. Django executes SQL code in the background with the model and describes the results with Python's data structure. Django also uses models to present advanced concepts that SQL cannot handle.
The first model:
Database structure: books/authors/publishers
Assume:
One author has a surname, a name and an Email address.
Publishers have names, addresses, cities, provinces, countries, websites;
Books have title and date of publication.
Books have one or more authors (many-to-many relationships with authors) and only one publisher (one to many relationships with publishers, also known as foreign key s);
The first step is to describe them in python code and add the following code to models.py:
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToMany(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
Be careful:
Each model corresponds to a single database table, and each attribute is also a field in the table. The attribute name is the field name, and its type (eg: CharFiled) corresponds to the dictionary type (eg: varchar) of the database.
Take the Publisher module as an example, which is equivalent to the following table (using the SQL statement CREATE TABLE):
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
);
Be careful:
Each data table corresponds to a class. The exception to this rule is the many-to-many relationship. eg: In this case, 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 the authors field. Instead, Django creates an additional table (many-to-many join tables) to handle the mapping between books and authors.
There is no explicit definition of any primary key for these models in this example. Unless you specify it separately, Django automatically generates a self-growing integer primary key field for each model, and each Django model requires a separate primary key.
A comma should also be added at the end of INSTALLED_APPS, because this is a tuple element, each tuple element is followed by a comma, whether it has only one element or not, in order to avoid forgetting to add a comma.
Each app in ISNTALLED_APPS uses Python's path description, packet's path, and decimal point "..." interval.
Next, you can create database tables. First, verify the validity of the model with the following commands:
python manage.py validate
In the new version of Django, however, the following commands are used to verify:
python manage.py check
If there are errors, the error output will give very useful scrubbing information to help correct the model.
If there are no errors, the system will return:
system check identified no issues (0 silenced) System Check No Error (0 Silence)
The model is validated correctly. Run the following command to generate the CREATE TABLE statement:
python manage.py makemigrations books
Migrations for 'books':
0001_initial.py:
- Create model Author
- Create model Book
- Create model Publisher
- Add field publisher to book
python manage.py sqlmigrate books 0001
BEGIN;
--
-- Create model Author
--
CREATE TABLE `books_author` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `first_name` varchar(30) NOT NULL, `last_name` varchar(40) NOT NULL, `email` varchar(254) NOT NULL);
--
-- Create model Book
--
CREATE TABLE `books_book` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `title` varchar(100) NOT NULL, `publication_date` date NOT NULL);
CREATE TABLE `books_book_authors` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `book_id` integer NOT NULL, `author_id` integer NOT NULL);
--
-- Create model Publisher
--
CREATE TABLE `books_publisher` (`id` integer AUTO_INCREMENT 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);
--
-- Add field publisher to book
--
ALTER TABLE `books_book` ADD COLUMN `publisher_id` integer NOT NULL;
ALTER TABLE `books_book` ALTER COLUMN `publisher_id` DROP DEFAULT;
ALTER TABLE `books_book_authors` ADD CONSTRAINT `books_book_authors_book_id_ed3433e7_fk_books_book_id` FOREIGN KEY (`book_id`) REFERENCES `books_book` (`id`);
ALTER TABLE `books_book_authors` ADD CONSTRAINT `books_book_authors_author_id_984f1ab8_fk_books_author_id` FOREIGN KEY (`author_id`) REFERENCES `books_author` (`id`);
ALTER TABLE `books_book_authors` ADD CONSTRAINT `books_book_authors_book_id_8714badb_uniq` UNIQUE (`book_id`, `author_id`);
CREATE INDEX `books_book_2604cbea` ON `books_book` (`publisher_id`);
ALTER TABLE `books_book` ADD CONSTRAINT `books_book_publisher_id_189e6c56_fk_books_publisher_id` FOREIGN KEY (`publisher_id`) REFERENCES `books_publisher` (`id`);
COMMIT;
Be careful:
The above two commands: Python management. py makemigrations books, Python management. py sqlmigrate books 0001, do not really create data tables in the database, but just print out the SQL statements, so as to make it easy to see what Django will do. If you need to create data tables, you can copy the SQL statements to the database client to execute, but Django provides a more. A simple way to submit SQL statements to a database: Python management.py migrate
This command only exists after version 1.9. It used to use syncdb command and no longer applies to the new version. After executing the above command, you will see the following:
python manage.py migrate
Operations to perform:
Apply all migrations: admin, contenttypes, books, auth, sessions
Running migrations:
Rendering model states... DONE
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying books.0001_initial... OK
Applying sessions.0001_initial... OK
Running the command again doesn't happen because you haven't added a new model or app, so it's safe to run the command again because it doesn't repeat the execution of the SQL statement.
Running Python management. py DB shell will go directly to the SQL client. This example uses MySQL, so after running, it will go directly to the MySQL client.
Basic Data Access
Once models are created, Django automatically provides advanced Python API s for these models, runs Python management.py shell and enters the following:
python manage.py shell
Python 2.7.10 (default, Oct 14 2015, 16:09:02)
[GCC 5.2.1 20151010] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>>
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',
... city='Berkeley', state_province='CA', country='U.S.A',
... website='http://www.apress.com/')
>>> p1.save()
>>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.',
... city='Cambridge', state_province='MA', country='U.S.A',
... website='http://www.oreilly.com/')
>>> p2.save()
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
>>>
Work done by the above code:
First, we import the Publisher model class, through which we can interact with tables containing publishers.
Next, an instance of the Publisher class is created and the values of the fields "name, address" and so on are set.
Call the save() method of the object and save it to the database. Django executes an INSERT statement in the background.
Finally, the Publisher.objects attribute is used to get publisher information from the database. There are many ways to get publisher information. The Publisher.objects.all() method is used to get all objects of the Publisher class in the database. Behind the scenes of this operation, Django executes a SELECT statement in the background.
If you need to complete the creation and storage of objects to the database in one step, use the "objects.create()" method, as follows:
>>> p1 = Publisher.objects.create(name='Apress',
... address='2855 Telegraph Avenue',
... city='Berkeley', state_province='CA', country='U.S.A.',
... website='http://www.apress.com/')
>>> p2 = Publisher.objects.create(name="O'Reilly",
... address='10 Fawcett St.', city='Cambridge',
... state_province='MA', country='U.S.A.',
... website='http://www.oreilly.com/')
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
String Representation of Adding Modules
When we print Publisher, we don't get the information we want. To solve this problem, we just need to add a method _unicode_() to the Publisher object. This method will tell Python how to display the object Unicode and modify the models.py under books.
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
def __unicode__(self):
return self.name
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
def __unicode__(self):
return self.title
The _unicode_() method of Publisher and Book objects simply returns their names and titles, while the _unicode_() method of Author objects simply returns the values of the first_name and last_name fields joined by spaces.
If the _unicode_() method returns an integer number instead of a Unicode object, it throws a "TypeError" and prompts, "coercing to Unicode: need string or buffer, int found".
Be careful:
Django uses Unicode objects in all aspects of its interior. In model objects, Unicode objects are used for retrieval and matching operations, Unicode objects are used for interaction between view functions, and Unicode objects are also used for rendering templates. Usually, we don't have to worry about whether the coding is correct or not, the background will handle it well.
Verify again the effect of the modified models:
root@blackromantic:/home/zxz/djcode/mysite# python manage.py shell
Python 2.7.10 (default, Oct 14 2015, 16:09:02)
[GCC 5.2.1 20151010] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Apress>, <Publisher: O'Reilly>]
Finally, _unicode_() is also a good example of how we add behavior to the model. Django's model defines not only the structure of database tables for objects, but also the behavior of objects.
Insert and update data
Publisher is used to update all data directly. After calling save() method, it is saved to database, which is equivalent to INSERT statement in SQL.
Publisher is used to update a piece of data directly. After calling save(), it is saved to the database, which is equivalent to UPDATE statement in SQL.
Choose the object
It is necessary to create a new database and update the data in it, but for web applications, it is more often to retrieve and query the database.
For example, we already know how to extract all records from a given model:
>>> Publisher.objects.all()
[<Publisher: Apress>, <Publisher: O'Reilly>]
This is equivalent to an SQL statement:
SELECT id, name, address, city, state_province, country, website FROM books_publisher;
Publisher.objects.all():
- Firstly, there is a defined model Publisher, which is necessary. To find data, we need a model to obtain data.
- Secondly, the object attribute, which is called manager, manages all table-level operations for data inclusion and most important data queries. All models automatically have an object manager, which is used when looking for data.
- Finally, there is the all() method, which returns all records in the database, although the object looks like a list, it is actually a QuerySet object, which is a collection of some records in the database.
Data filtering
Usually we only operate on a part of the data. In the Django API, "filter()" method is used to filter the data:
>>> from books.models import Publisher
>>> Publisher.objects.filter(name='Apress')
[<Publisher: Apress>]
>>>
filter() is converted into WHERE SQL statements based on keyword parameters. The above example is equivalent to:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress';
Multiple parameters can be passed to filter() to narrow the query range:
>>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress>]
Converting to an SQL statement is:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = 'U.S.A.'
AND state_province = 'CA';
The default = operator for SQL is an exact match, and other types of lookups can also be used:
>>> Publisher.objects.filter(name__contains="press")
[<Publisher: Apress>]
There are double underscores between name and contains. Django also uses double underscores to indicate some special operations. The contains section here is translated by Django into the LIKE statement of SQL:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name LIKE '%press%';
Other types are:
icontains: Case-independent LIKE
startwith, endwith, range: BETWEEN query equivalent to SQL
Getting a single object
If we want to get a single object, we can use the "get()" method:
>>> Publisher.objects.get(name="Apress")
<Publisher: Apress>
This returns a single object, not a list (more accurately, QuerySet).
If not a single object, but multiple objects are returned, an exception is thrown:
>>> Publisher.objects.get(country="U.S.A")
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 122, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 391, in get
(self.model._meta.object_name, num)
MultipleObjectsReturned: get() returned more than one Publisher -- it returned 2!
>>>
If the result of the query does not exist, an exception is thrown:
>>> Publisher.objects.get(name="Penguin")
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 122, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 387, in get
self.model._meta.object_name
DoesNotExist: Publisher matching query does not exist.
>>>
This DoesNotExist exception is an attribute of the Publisher model class, Publihser.DoesNotExist. In your application, you can capture and handle this exception:
try:
p = Publisher.objects.get(name='Apress')
except Publihser.DoesNotExist:
print "Apress isn't in the database yet."
else:
print "Apress is in the database."
Data Sorting
In Django applications, if you want to learn the search results according to the value of a field, such as in alphabetical order, you can use the "order_by()" method:
>>> Publisher.objects.order_by("name")
[<Publisher: Apress>, <Publisher: O'Reilly>]
Equivalent to an SQL statement:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name;
If you need to sort by multiple fields (the second field will be used when the value of the first field is the same), you can use multiple parameters:
>>> Publisher.objects.order_by("state_province", "address")
[<Publisher: Apress>, <Publisher: O'Reilly>]
You can also specify reverse sorting by adding a minus prefix before it:
>>> Publisher.objects.order_by("‐name")
[<Publisher: O'Reilly>, <Publisher: Apress>]
Although this approach is flexible, it is a bit verbose to use "order_by()" every time. Most of the time, only certain fields are sorted. In this case, Django can use the default sorting method of the specified model:
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
def __unicode__(self):
return self.name
class Meta:
ordering = ['name']
ClassMeta is embedded in the definition of Publisher class. You can use Meta class in any model class to set some options related to the feature model. If you set this option, unless you specifically use order_by(), when you use Django's database API to retrieve, the relevant return of Publisher object will press n by default. Sort the ame field.
Chain Query
If filtering and sorting queries are performed simultaneously, they can be simply written in the form of a "chain":
>>> Publisher.objects.filter(country='U.S.A').order_by("-name")
[<Publisher: O'Reilly>, <Publisher: Apress>]
Converting to SQL queries is a combination of WHERE and ORDER_BY:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = 'U.S.A'
ORDER BY name DESC;
Restrict returned data
To extract a fixed number of records, for example, to display only the first, you can use the standard Python list to tailor statements:
>>> Publisher.objects.order_by('name')[0]
<Publisher: Apress>
Equivalent to an SQL statement:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
LIMIT 1;
Similarly, Python's range-slicing grammar can be used to extract a specific subset of data:
>>> Publisher.objects.order_by('name')[0:2]
Equivalent to an SQL statement:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
OFFSET 0 LIMIT 2;
But Python's negative index is not supported:
>>> Publisher.objects.order_by('name')[‐1]
Traceback (most recent call last):
...
AssertionError: Negative indexing is not supported.
But other methods can be used, such as modifying the order_by() statement slightly:
>>> Publisher.objects.order_by('‐name')[0]
Update multiple objects
The save() method updates all columns in a row, but if we want to update some columns in a row, such as changing the name of Apress Publisher from "Apress" to "Apress Publishing", we can call the update() method of the QuerySet object:
>>> Publisher.objects.filter(id=52).update(name='Apress Publishing')
Note: Let's assume that the ID of Apress is 52.
Equivalent to an SQL statement:
UPDATE books_publisher
SET name = 'Apress Publishing'
WHERE id = 52;
The update() method is valid for any result set, which means that multiple records can be updated at the same time, such as changing the count field values of all Publisher s from'U.S.A'to'USA':
>>> Publisher.objects.all().update(country='USA')
2
The update() method returns an integer value representing the number of records affected, which in the example above is 2.
delete object
To delete an object in a database, you only need to call the delete() method of the object:
>>> p = Publisher.objects.get(name="O'Reilly")
>>> p.delete()
>>> Publisher.objects.all()
[<Publisher: Apress Publishing>]
Similarly, delete() method can be called on the result set and multiple records can be deleted at the same time:
>>> Publisher.objects.filter(country='USA').delete()
>>> Publisher.objects.all().delete()
>>> Publisher.objects.all()
[]
Be careful when deleting data. In order to prevent the incorrect deletion of all data in a table, Django requires that all() be displayed when deleting all data in a table.
>>> Publisher.objects.delete()
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Manager' object has no attribute 'delete'
Once you use all() method, all data will be deleted, remember!