您的位置:首页 > 编程语言 > Go语言

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

2018-02-04 18:03 573 查看
定义模型:

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()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: