Django进阶——模型的高级用法

定义模型:

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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值