Django model 层之Making Query总结
实践环境
Python版本:python-3.4.0.amd64
下载地址:https://www.python.org/downloads/release/python-340/
Win7 64位
Django 1.11.4
下载地址:https://www.djangoproject.com/download/
API交互
MySQL数据库为例,假设项目目录结构如下:
mysite/
myapp/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
models.py内容如下:
from django.db import models
# Create your models here.
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class Book(models.Model):
book_name = models.CharField(max_length=30)
borrower = models.ForeignKey(Person, to_field='id', on_delete=models.CASCADE)
class Blog(Book):
author = models.CharField(max_length=50)
class Store(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
last_update = models.DateField(auto_now=True)
class Fruit(models.Model):
store = models.ManyToManyField(Store)
name = models.CharField(max_length=100)
onsale_date = models.DateField()
class News(models.Model):
title = models.CharField(max_length=20)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
进入到项目根目录下,运行python
cd /d F:\project\Django\MyProjects\mysite\
python
>>> import os
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>>
说明:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project_name.settings")
添加以上代码避免出现以下问题:
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing
>>> import django
>>> django.setup()
说明:
添加以上代码,避免出现以下问题
……
raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
创建对象
>>> from myapp.models import Person
说明:
from app_name.models import module
python当前目录为项目根目录下,models位于app目录下,所以如上 app_name.models
>>> person = Person(first_name="ke", last_name="shou")
>>> person.save()
执行save()方法时,等同于执行以下sql INSERT语句。
INSERT INTO `myapp_person` (`id`, `first_name`, `last_name`) values('1','ke','shou');
说明:创建对象时也可以使用字典解引的方式,如下:
>>> fields_dict = {"first_name":"ke", "last_name":"shou"}
>>> person = Person(**fields_dict)
创建包含外键field的对象
>>> from myapp.models import Person,Book
方式1:创建对象时,外键Field名称要写为“外键Field名称_id”的形式
>>> book1 = Book(borrower_id='1', book_name='mybook')
>>> book1.save()
注意:如果,外键Field名称直接使用所在模块类中的定义的类属性名称,直接设置值为外键Field的值,则会提示外键Field的值必须为外键Field所关联类的实例,如下:
>>> book1 = Book(borrower='1', book_name='mybook')
……
self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "'1'": "Book.borrower" must be a "Person" instance.
方式2:解决以上依赖问题
>>> person2 = Person(first_name="ku", last_name="shou")
>>> person2.save()
>>> book2 = Book(borrower=person2, book_name='mybook2')
>>> book2.save()
创建包含多对多Field的对象
针对多对多Field,除了建立model对应的表外,django还会新增一张关联表:app名称_包含ManyToManyField类型Field的model名称_ManyToManyField类型Field指定的model名称(例中myapp_fruit_store),存放两个model对应的表对应记录的id
>>> from myapp.models import Store,Fruit
>>> amy_store = Store.objects.create(name='aimi')
SELECT * FROM `myapp_store` WHERE `name` = 'aimi';
显示:
id name last_update
7 aimi 2018-03-25
说明:以create方式建立对象,无需执行obj.save()函数就会在表新增对应的记录,如上,如果添加,amy_store.save()代码,则会在此基础上,再新增一条记录。内容和amy_store对象的一样。
注意:针对多对多,不能按以下方式创建对象,会报错:
>>> apple = Fruit(name='apple',onsale_date='2018-03-24')
>>> apple.save()
SELECT * FROM `myapp_fruit` WHERE `name` = 'apple';
显示:
id name onsale_date
3 apple 2018-03-24
注意:调用add之前,必须保证对象自身已存在,即已创建,否则会报类似如下的错误:
ValueError: "<Fruit: Fruit object>" needs to have a value for field "id" before this many-to-many relationship can be used.
由此可见,我们不能通过类似以下语句,一次性创建包含ManyToManyField类型Field的对象
banana = Fruit(store=aimi_store,name='banana',
onsale_date='2018-03-24')
banana.save()
到目前为止,关联表myapp_fruit_store里还是没有记录
>>> apple.add(aimi_store)
SELECT * FROM `myapp_fruit_store`
显示:
id fruit_id store_id
1 3 7
修改对象
person.last_name="yu"
person.save()
执行save()方法时,等同于执行以下sql UPDATE语句。
UPDATE `myapp_person` SET last_name ='yu' where id =1;
修改包含外键的对象
清空Person,Book moduel关联的表数据后,执行以下操作
例:
>>> person = Person(first_name='ke', last_name="shou")
>>> person.save()
>>> book = Book(book_name="yueding", borrower=person)
>>> book.save()
SELECT * FROM myapp_person
显示:
id first_name last_name
1 ke shou
SELECT * FROM myapp_book
显示:
id book_name borrower_id
1 yueding 1
>>> person = Person(first_name='yu', last_name='lai')
>>> person.save()
>>> book.borrower = person
>>> book.save()
SELECT * FROM myapp_person
显示:
id first_name last_name
1 ke shou
2 yu lai
SELECT * FROM myapp_book
显示:
id book_name borrower_id
1 yueding 2
修改包含多对多Field的对象
add
增加model对象到关联对象,即在model对应表中增加关联记录
>>> ximi_store = Store.objects.create(name='ximi')
>>> apple = Fruit.objects.get(id=3)
>>> apple.store.add(ximi_store)
SELECT * FROM `myapp_fruit_store`
显示:
id fruit_id store_id
1 3 7
2 3 8
结果如上,新增一条关联记录,关联新增的ximi_store
当然,我们也可以一次性关联多个对象
>>> xima_store = Store.objects.create(name='xima')
>>> masu_store = Store.objects.create(name='masu')
>>> apple.store.add(xima_store, masu_store)
SELECT * FROM `myapp_fruit_store`
显示:
id fruit_id store_id
1 3 7
2 3 8
3 3 9
4 3 10
remove
从已关联对象中,删除指定关联对象
承接add
>>> apple.store.remove(masu_store)
SELECT * FROM `myapp_fruit_store`
显示:
id fruit_id store_id
1 3 7
2 3 8
3 3 9
注意:上面是基于“add”中操作的,如果还没获取对象,则需要通过类似 model_name.objects.get(id=1)的方式,先获取对象,然后操作对象。
set
注:以下基于remove之后的操作
>>> gami_store = Store.objects.create(name='gami')
>>> gama_store = Store.objects.create(name='gama')
>>> new_list = [gami_store, gama_store]
>>> apple.store.set(new_list)
SELECT * FROM `myapp_store`
显示:
id name last_update
7 aimi 2018-03-25
8 ximi 2018-03-25
9 xima 2018-03-25
10 masu 2018-03-25
11 gami 2018-03-25
12 gama 2018-03-25
SELECT * FROM `myapp_fruit_store`
显示:
id fruit_id store_id
6 3 11
5 3 12
如上,关联的对象,全部被替换为最新的了
clear
清空所有已关联对象
>>> apple.store.clear()
结果myapp_fruit_store表中的记录全部被清空了。
参考链接:
检索对象
检索所有对象
例:
>>> person = Person(first_name="ke", last_name="shou")
>>> person.save()
>>> all_entries = Person.objects.all()
>>> all_entries
<QuerySet [<Person: Person object>]>
>>> print(all_entries.query) # 查看获取结果集执行对sql语句
说明:
all()方法会返回数据库表中所有记录的结果集,等同于以下sql SELECT 语句
SELECT * FROM `myapp_person`
另外,我们可以通过list(QueryResultSet)把QuerySet类型的查询结果转为列表类型
通过过滤器检索特定对象
例:
>>> entries = Person.objects.filter(first_name='ke')
说明:
等同于
>>> entries = Person.objects.all().filter(first_name='ke')
执行以上filter方法,等同于执行以下SQL方法
SELECT * FROM `myapp_person` WHERE first_name = 'ke'
>>> entries = Person.objects.exclude(last_name='yu')
执行以上exclude方法,等同于执行以下SQL方法
SELECT * FROM `myapp_person` WHERE first_name != 'yu'
链式过滤器
例:
>>> Person.objects.filter(first_name='ke').filter(last_name='shou')
说明:先过滤出first_name值为ke的,然后再从这里面筛选出last_name为 shou的。
等同于
>>> Person.objects.filter(first_name='ke', last_name='shou')
>>> Person.objects.filter(first_name='ke').exclude(last_name='shou')
说明:先过滤出first_name值为ke的,然后再从这里面筛选出last_name不为 shou的
当然,也可以拆分成多条语句
>>> q1 = Person.objects.filter(first_name='ke')
>>> q2 = q1.exclude(last_name='shou')
>>> print(q2)
注意:只有真正用到查询结果时,才会执行数据库操作,比如上述代码,只有执行最后一行,print(q2)时才会真正去数据库查询。
注意:exclude并不是filter的完全实现。如下:
SELECT * FROM `myapp_person`
显示:
id first_name last_name
1 ke shou
2 yu lai
3 ke lai
4 yu laiyu
SELECT * FROM `myapp_book`
显示:
id book_name borrower_id
1 yueding 2
2 duzhe 1
3 zhazhi 2
4 shenghuo 3
5 qinglv 4
获取myapp_person表记录,排除在myapp_book表中存在外键引用,且对应记录book_name为yueding, id=1的。
>>> persons = Person.objects.exclude(book__book_name='yueding', book__id=1)
>>> for person in persons:
... print(person.first_name, person.last_name, person.id)
...
ke shou 1
ke lai 3
yu laiyu 4
注意:
1、“反向查找”,条件左侧表达式填写格式:model名称__field名称
2、“正向查找”,不能按以上方式查找,比如以下,会报错:
>>> books = Book.objects.exclude(Person__first_name='ke', Person__last_name='shou')
反向查找和正向查找是我个人定义。定义不太好表达,具体参考以上例子。
如果结合filter方法来实现,则可采用“嵌套”的方式
>>> persons = Person.objects.exclude(book__in=Book.objects.filter(book_name='yueding', id=1))
>>> for person in persons:
... print(person.first_name, person.last_name, person.id)
...
ke shou 1
ke lai 3
yu laiyu 4
>>>