django 增加数据库字段,django开发api
通过扩展Django数据库API支持全文搜索
关于这篇文章的翻译,请参考http://www.mercurytide.com/的原文。
介绍姜戈
Django是一个开源的Web应用程序框架,用它的创建者的话说,就是“鼓励快速开发和干净有效的设计”。它是用Python编写的,提供了各种组件来创建高质量的Web应用程序,包括ORM(对象关系映射器)框架、支持所有功能的模板系统、URL分配器、会话管理、安全认证和许多其他东西。
框架的一个有价值的衡量标准是满足开发者需求的扩展是否简单。在这里,我们将介绍Django的数据库API,并通过扩展Django的全文搜索功能以支持MySQL来展示其灵活性。
本文包含的源代码已经在公共区域发布。
Django的数据库API
Django的ORM提供了丰富的API来创建数据库查询。这个API可以将应用程序开发人员与SQL语句的细节隔离开来,但它仍然以高效的方式支持复杂选择标准的查询。这种方法的另一个显著优点是,它完全避免了“SQL注入攻击”的可能性,应用程序开发人员不再需要直接将数据值插入SQL语句中。
从数据库中获取对象后,形成“QuerySet”查询集,是一条SQL选择语句的抽取结果。QuerySet提供了一些方法来减少结果集和对象集之间匹配/转换的细节,其中一些方法就像SQL语句中的WHERE条件子句——实际上,在幕后,QuerySet创建一个SQL语句,并作为它的方法被调用。QuerySet实例是从模型类的管理器实例中获得的,这些实例通常称为对象。以下是使用QuerySet的一些示例:
#获取包含所有文章的查询集
articles=Article.objects.all()
#仅包含今年(2007年)之前撰写的文章
articles=articles . filter(posted _ date _ _ lt= 2007-01-01 )
#除了我写的文章
articles=articles . exclude(author _ _ exact= Richard )
#最后按点击率和出版日期升序排序。
articles=articles.order_by(评级,发布日期)
QuerySet可以很容易的过滤和排序,并且在求值时有延迟:这些动作在query set内部操作SQL语句,这些语句不会被执行,除非你尝试通过迭代器或分片来访问query set的记录。
#获取前五篇文章,然后才访问数据库
a=条款[:5]
为了扩展这个接口,我们将开发一个manager子类和一个query set子类,但在此之前,我们先简单描述一下MySQL的全文搜索。
和MySQL全文搜索
MySQL内置了全文搜索引擎,但是没有专门的库(比如Lucene和Xapian)强大。它集成了数据库引擎和查询语法,因此易于在数据库驱动的应用程序中使用。这里我们只看它对“自然语言”查询的支持。请查看MySql文档了解其他细节。
MySQL的全文搜索功能可以通过在数据表的一个字段或一些列字段中创建全文索引来激活。无论行数据是被写入、更新还是删除,这些索引都会自动更新,因此搜索结果都是最新的,永远不会过期。创建索引的语句可以这样使用:
在要索引的表上创建全文索引索引名(要索引的表中的列名)
使用搜索匹配.根据表达式指定搜索的列名和搜索的文本:
匹配(要搜索的列名)和(要搜索的文本)
对于自然语言查询,使用该表达式的方法如下:
选择标题,匹配(标题,文本)对( Django框架)
作为“相关性”
来自全文_文章
WHERE MATCH(标题,文本)反( Django框架)
这将返回所有匹配文本“Django and framework”的文章的标题(titles)和适当的分数(relevance score)。默认情况下,它们按相关性降序排列。不要担心重复匹配.针对这个语句中的表达式——MySQL会发现它们是相同的,并且只会执行一次这个搜索。值得注意的是,传递给MATCH的列必须与创建索引的数据库中的列一致。
扩展的数据库API支持搜索
Django的设计原则之一是“一致性和连续性”,这对扩展非常重要。为了使全文搜索界面与Django的其他部分保持一致,这个扩展应该使用Manager和QuerySets,这样就可以以同样的方式使用。事实上,这意味着程序员可以编写如下语句:
article . objects . search(“Django爵士吉他”)
article . objects . filter(posted _ date _ _ gt= 2006-07-01 )。搜索(“Django Python”)
这些语句将返回筛选后的查询集本身。为了实现这个目标,我们将开发一个名为SearchQuerySet的QuerySet的子类来提供search()方法,并创建一个匹配.针对表达式来填充SQL语句;创建一个名为SearchManager的Manager子类,以返回SearchQuerySet子类。因为这个管理类也提供了很多QuerySet方法以方便使用,所以为了保持一致,SearchQuerySet也应该提供一个search()方法。代码如下:
从django.db导入模型,后端
类search query set(models . query . query set):
def __inti__(self,model=None,fields=None):
超级(SearchQuerySet,self)。__init__(型号)
自我。_search_fields=字段
定义搜索(自身,查询):
meta=self.model._meta
#从模型中获取数据表名称和列名称
#以“表名”的样式。列名
columns=[meta.get_field(name,many_to_many=False)。圆柱
以自我的名义。_搜索_字段]
全名=[%s.%s %
(后端.报价名称(meta.db_table),后端.报价名称(列))
对于列中的列]
#创建匹配.反对表达
fulltext_columns=“,”。加入(全名)
match_expr=(MATCH(%s)对(% % s)% full text _ columns)
#添加额外的选择和位置选项
return self . extra(select={ relevance :match _ expr },
其中=[匹配表达式],
params=[查询,查询])
类SearchManager(模型。经理):
def __init__(self,fields):
超级(SearchManager,self)。__init__()
self.search_fields=字段
def get_query_set(self):
返回SearchQuerySet(self.model,self。_搜索_字段)
定义搜索(自身,查询):
返回self.get_query_set()。搜索(查询)
在这里,SearchQuerySet.search()向Django请求表和列的名称,创建一个匹配.然后在一行中添加查询的SELECT和WHERE子句。
很方便。姜戈自己做了所有的实际工作。类中的_meta对象存储了关于模型及其字段的所有“元信息”,但这里我们只需要表名和字段名(SearchQuerySet实例初始化时,它被告知将搜索哪些)。
QuerySet.extra()方法提供了一种简单的方法来添加扩展列、WHERE子句表达式和对QuerySet内部SQL语句的表引用:select参数将列名映射到一个表达式(可以认为是“SELECT expression AS alias”),其中parameter是由WHERE子句组成的表达式列表,params参数是SQL语句中嵌入字符串“%s”的替换值列表。
经理呢?如上所述,它必须返回一个SearchQuerySet实例来替换普通的QuerySet。幸运的是,Manager类编写了这个方法,它有一个get_query_set()方法来返回一个适当的QuerySet子类的实例,每当需要为一个适当的管理类创建一个新的QuerySet实例时,都会调用它,所以重写这个get_query_set()方法来返回一个SearchQuerySet是很简单的。当创建SearchQuerySet的实例时,它传入要搜索的字段,这些字段已经在它自己的构造函数中提供了。我们也希望searchManager实现一个方便的search()方法,但是我们实际上负责充当SearchQuerySet.search()的代理。
使用搜索组件
我们将演示这些子类的使用。下面是一篇发表在网站上的文章的简单模型;因此可以对其进行搜索,我们创建了一个SearchManager实例,并将其分配给对象:
从django.db导入模型
从fulltext.search导入搜索管理器
类文章(模型。型号):
发布日期=型号。日期字段(db_index=True)
标题=模型。CharField(maxlength=100)
文本=模型。文本字段()
#用SearchManager获取对象,并告诉他需要搜索哪些字段。
objects=SearchManager((title , text ))
班级管理员:
及格
def __str__(self):
返回“% s(% s)%(self . title,self.posted_date)
所有文章都有标题、正文和发表日期。我们将为数据库中的title和TEXT列定义一个全文索引,并将相应字段名称的元组传递给SearchManager实例。下面是创建索引的SQL语句。
创建全文索引全文_文章_标题_文本
关于fulltext_article(标题,正文);
假设有一个Django项目,一个应用程序包含一个文章模型和一个填充了适当文章数据的数据库,那么可以在Python的交互式解释器中轻松演示全文搜索:
#这里有多少篇文章?
len(Article.objects.all())
#查找关于框架的文章
Article.objects.search(“框架”)
#显示这些文章的适当分数
[(a,a .相关性)
对于article . objects . search( framework )]中的
#将这些文章的搜索结果限制在6月出版日期之前
Article.objects.search(框架)。筛选器(发布日期__lt=2006-06-01 )
#请注意,filter()也返回一个SearchQuerySet:
article . objects . filter(posted _ date _ _ lt= 2006-06-01 )。搜索(“框架”)
注意的最后一点
现在,我想让你知道一个秘密:从2006年6月开始,Django就支持一个搜索运营商查询MySQL的全文搜索。
#这里使用的是布尔搜索模式,不是自然语言查询。
article . objects . filter(title _ _ search= Django-Rails )
尽管如此,本文中展示的技术特性仍然可以用来创建数据库API扩展,以支持任何SQL特性,无论它支持全文搜索、分组、聚合查询、任何其他SQL特性还是特定的数据库扩展。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。