定义模型:
from django.db import models
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 __str__(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 __str__(self):
return '%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 __str__(self):
return self.title
一、访问外键值
访问 ForeignKey 类型的字段时,得到的是相关的模型对象。
>>>b = Book.objects.get(id=50)
>>>b.publisher
<Publisher: Apress Publishing>
>>>b.publisher.website
'http://www.apress.com/'
二、ForeignKey 字段反向访问
book_set 就是一个 QuerySet 对象。book_set 属性是生成的:把模型名的小写形式与 _set 连在一起。
>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]
三、访问多对多值
查看一本的的作者,得到的结果是 QuerySet 值
>>> b = Book.objects.get(id=50)
>>> b.authors.all()
[<Author: Adrian Holovaty>, <Author: Jacob Kaplan-Moss>]
>>> b.authors.filter(first_name='Adrian')
[<Author: Adrian Holovaty>]
>>> b.authors.filter(first_name='Adam')
查看一位作者撰写的所有图书,使用 author.book_set
>>> a = Author.objects.get(first_name='Adrian',
last_name='Holovaty')
>>> a.book_set.all()
[<Book: The Django Book>, <Book: Adrian's Other Book>]
四、管理器
在 Book.objects.all() 语句中,objects 是个特殊的属性,即模型的管理器(manager),我们通过它查询数据库。
-
模型的管理器是 Django 模型用于执行数据库查询的对象。一个 Django 模型至少有一个管理器, 而且可以自定义管理器,定制访问数据库的方式。自定义管理器可能出于两方面的原因:添加额外的管理器 方法和(或)修改管理器返回的 QuerySet。
- 添加管理器
为 Book 模型添加一个管理器方法 title_count(),它的参数是一个关键字,返回书名中 包含关键字的图书数量
from django.db import models
# ... Author 和 Publisher 模型省略了 ...
#定义第一个管理器
class BookManager(models.Manager):
def title_count(self, keyword):
return self.filter(title__icontains=keyword).count()
#定义第二个管理器
class DahlBookManager(models.Manager):
def get_queryset(self):
return super(DahlBookManager,self).get_queryset().filter(author='Roald Dahl')
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models.IntegerField(blank=True, null=True)
objects = models.Manager() # 默认的管理器
dahl_objects = DahlBookManager() # 专门查询 Dahl 的管理器
def __str__(self):
return self.title
使用
Book.objects.title_count('django')
Book.dahl_objects.all()
Book.dahl_objects.filter(title='Matilda')
Book.dahl_objects.count()
五、修改模型默认方法
一系列封装数据库行为的模型方法有时也需要自定义。尤其是 save() 和 delete(),经常需要修改它们的 运作方式。
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
#覆盖默认的save方法
def save(self, *args, **kwargs):
do_something()
super(Blog, self).save(*args, **kwargs) # 调用“真正的”save () 方法
do_something_else()
六、执行原始 SQL查询
Manager.raw(raw_query, params=None, translations=None)
#模型
class Person(models.Model):
...
#使用原始查询('myapp_person'表示myapp下的Person模型)
for p in Person.objects.raw('SELECT * FROM myapp_person'):
...
- 把查询中的字段映射到模型字段上
方式一:
Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')
方式二:
Person.objects.raw('''SELECT first AS first_name,last AS last_name,bd AS birth_date,pk AS id,FROM some_other_table''')
方式三:
name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
Person.objects.raw('SELECT * FROM some_other_table',translations=name_map)
- 索引和切片
first_person = Person.objects.raw('SELECT * FROM myapp_person LIMIT 1')[0]
- 执行条件查询
正确写法:
Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])
错误写法:
query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname
使用 params 参数能完全避免 SQL 注入攻击。这是一种常见的漏洞,攻击者能设法向数据库中 注入任意的 SQL。如果使用字符串插值,迟早有一天你会变成 SQL 注入的牺牲者。记住,一 定要使用 params 参数,这样便能得到保护。
七、直接执行自定义的 SQL
①获取连接:django.db.connection
②获取游标对象:connection.cursor()
③执行SQL:cur- sor.execute(sql, [params])
④获取结果: cursor.fetchone() 或 cursor.fetchall()
- 示例:
from django.db import connection
def my_custom_sql(self):
cursor = connection.cursor()
cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
row = cursor.fetchone()
return row
使用多个数据库时,可以使用 django.db.connections 获取指定数据库的连接(和游标)。django.db.connec-tions 是一个类似字典的对象,可以使用别名取回指定连接:
from django.db import connections
cursor = connections['my_db_alias'].cursor()