本文的主要首席执行官将介绍如何解决Django惯性查询和Django过滤查询的相关内容。我希望这对每个人都会有所帮助。让我们来看看。
本文目录清单:
1.在查询期间向DateTimeField的问题提供建议2.2014-06-15 14:38:37.873873)时区支持活动。运行时间沃宁)
此警告的原因是Django被配置为使用TimeZone的DateTime格式,并且Date.Now不包括时区信息。
如果您不需要处理程序中的时区,则在django项目的设置中。您可以将其直接设置为“ use_tz = false”。models.deteTimeField(auto_now_add = true)和“ update_time = models.detetimefield(auto_now = true)”。
如果您仍然需要保持us_tz = true,则可以将其设置为“ default = dateTime.now()。替换(tzinfo = utc)”。
舞台开始时没有问题。例如,我们在模型中有一个员工表员工。在相应的表结构中,柱列表示员工位置。操作由模型完成(posity = params)完成。获得的员工信息内容仅由QuerySet和当前显示页面以及每个页面显示的记录数量计算,然后返回到前台页面以进行渲染显示。编码如下:
def get_employees(位置,开始,结束):
返回amploye.objects.filter(alert_time__lt = end,alert_time__gt = start)。过滤器(姿势__in =姿势)
@要求登录
def show(请求):
如果没有价值(请求):
返回render_to_response('none.html',
context_instance = requestContext(请求,'msg':'params error')
治愈
位置= request.request.get('posity')
time_range = request.request.get.get('time')
开始,end = time_range [0],time_range [1]
num_per_page,page_num = get_num(请求)
all_employees = get_employees(姿势,开始,结束)
#根据当前页面和每个页面显示的记录数量,获取正确的记录
员工=员工_events [(page_num-)*num_per_page:page_num*num_per_page]
返回render_to_response('show_employees.html',
context_instance = requestContext(
要求,
“员工”:员工,
'num_per_page':num_per_page,
'page_num':page_num,
'page_optings':[50,100,200]
治愈
治愈
运行后,您可以正确显示您查询的员工信息,并且查询速度很快。员工表具有不同位置的员工信息,不同类型的详细信息不同。假设员工有一个名为Infomation的专栏,则存储了员工的详细信息。Male','normanity':'dermanity','''':“医生”,'Motto':'只是做'},目前的需求是要显示更详细的员工信息。除了出发时间,还将筛选信息中的内容。这是查询中国国籍的设计师的一个例子。根据先前的代码,您需要进行一些修改。员工员工存储在MySQL中,而MySQL是一个ORM数据库。它不能像MongoDB那样提供更强大的聚合物函数,因此无法通过对象提供的方法执行。然后,您需要在类型后过滤数据并执行第二次遍历。它用于确定当前记录是否需要返回显示。在显示过程中,您需要计算基于num_per_page和page_num显示数据启动和终止位置的需求。
def get_employees(位置,开始,结束):
返回amploye.objects.filter(alert_time__lt = end,alert_time__gt = start)。过滤器(姿势__in =姿势)
def filter_with_nation(all_employees,normantity,num_per_page,page_num):
结果= []
pos =(page_num-)*num_per_page
CNT = 0
start = false
对于all_employes中的员工:
info = json.loads(员工。信息)
如果info.nationality!=国籍:
继续
#获得的数据可能不是主页,因此您需要跳过上一页
如果cnt == pos:
如果开始:
休息
CNT = 0
pos = num_per_page
start = true
如果开始:
result.append(员工)
退货员工
@要求登录
def show(请求):
如果没有价值(请求):
返回render_to_response('none.html',
context_instance = requestContext(请求,'msg':'params error')
治愈
位置= request.request.get('posity')
time_range = request.request.get.get('time')
开始,end = time_range [0],time_range [1]
num_per_page,page_num = get_num(请求)
all_employees = get_employees(姿势,开始,结束)
国籍= request.request.get.get('nationality')
员工= filter_with_nation(all_empoloyees,num_per_page,page_num)
返回render_to_response('show_employees.html',
context_instance = requestContext(
要求,
“员工”:员工,
'num_per_page':num_per_page,
'page_num':page_num,
'page_optings':[50,100,200]
治愈
治愈
编码完成后,当数据员工表数据很小时,测试找不到问题。当数据量很大并且数据查询数据很小时,代码就非常耗时。我们想象这是一家大型跨国公司,人员的交通量也很大,因此员工表的数据数量很大,这里的小国没有很多员工。例如,当员工时,前台页面进入了无尽的等待状态。在同一时间,监视过程的内存信息发现该过程的内存已经在增长。毫无疑问,该问题出现在Filter_with_nation函数中,这逐一遍历员工中的数据并分析每个数据。这不是一种有效的方法。
我在线检查了相关信息,并学到了:
Django的QuerySet是惰性的。使用过滤器语句进行查询。实际上,它不会运行数据库中的任何数据
只要您查询,数据库就会真正运行。引起查询的操作是:遍历querySet,切片,序列化和list(),querySet的len(len()方法和if语句
当它第一次进入循环并通过QuerySet时,Django从数据库中获取数据。在返回任何经过的数据之前,它将为内存中的每个数据创建一个实例,这可能会导致内存溢出。
以上解释了代码引起的现象。因此如何优化是一个问题。据说在互联网上说,当QuerySet非常巨大时,为了避免一次记忆加载,它可以使用迭代器迭代器()。()。()与以前相同,记忆将继续成长,前台页面正在等待。对此的解释是:使用itertor()将通过不存储高速缓存国际布局的结果来为您节省一些内存,但仍将从数据库中检索整个对象。
在这里,我们知道您不能一次遍历QuerySet中的所有记录,因此您只能切成QuerySet,每次占用块_size的大小,遍历数据的这一部分,然后累积。当达到所需号码时,返回满意度。对象列表,修改filter_with_nation函数:此处:
def filter_with_nation(all_employees,normantity,num_per_page,page_num):
结果= []
pos =(page_num-)*num_per_page
CNT = 0
start_pos = 0
start = false
而真:
员工= all_employees [start_pos:start_pos+num_per_page]
start_pos += num_per_page
对于emblayees的员工:
info = json.loads(员工,infomation)
如果info.nationality!=国籍:
继续
如果cnt == pos:
如果开始:
休息
CNT = 0
pos = num_per_page
start = true
如果开始:
result.append(opt)
CNT += 1
如果cnt == num_per_page或不事件:
休息
返回结果
运行上述代码时,查询速度速度更快,并且内存不会显着增加,并且效果得到了优化。本文的最初意图是记录我对Django中QuerySet的理解和使用,以及对于示例中的示例实际上,如果您需要记录员工的详细信息,最好扩展员工表,或创建表格,存储itdetails,而不是将所有信息放入字段中以避免在查询期间避免次要分析。
1.创建项目
运行以下命令来创建Django项目。项目名称是MySite:
$ django- addmin.py startproject mysite
创建的项目目录如下:
我的网站
e- manage.py
t - 锰矿
t- __init__.py
在──设置.py
s-或urls.py
。─— wsgi.py
1个目录,5个文件
阐明:
__init__.py:让Python将目录作为开发包所需的文件(即一组模块)。这是一个空文件,通常您不需要修改它。
Manage.py:命令行工具允许您通过多种方式与Django项目进行交互。类型python manage.py帮助查看它可以做什么。您不需要编辑此文件;在此目录中为方便起见是纯粹的。
settings.py:Django项目的设置或配置。
urls.py:项目的URL路由设置。目前,它是空的。
wsgi.py:wsgi Web应用程序服务器配置文件。有关更多详细信息,请检查如何使用WSGI部署
接下来,您可以修改settings.py文件,例如:修改Lagansy_code,设置时区time_zone
SIT_ID = 1
lanking_code ='zh_cn'
time_zone ='亚洲/上海'
use_tz = true
[时区]()功能在上方打开。您需要安装pytz:
$ sudo pip安装pytz
2.操作项目
在运行项目之前,我们需要创建一个数据库和表结构。我在这里使用的默认数据库:
$ python manage.py迁移
执行操作:
应用所有迁移:管理员,contenttypes,auth,sessions
运行迁移:
应用ContentTypes.0001_Initial ...确定
应用auth.0001_initial ...确定
应用管理员0001_Initial ...确定
应用sessions.0001_initial ...好的
然后开始服务:
$ python manage.py runserver
您将看到以下输出:
执行系统检查...
系统检查没有问题(0沉默)。
2015-02 1月28日:08:33
Django版本1.7.1,用户设置“ mysite.settings”
启动开发服务器
使用Control-C退出服务器。
这将在端口8000启动本地服务器,只能从您的计算机连接和访问。现在服务器正在运行,现在可以访问Web浏览器。它开始工作。
您还可以指定启动端口:
$ python manage.py runserver 8080
并指定的IP:
$ python manage.py runserver 0.0.0.0:8000
3.创建一个应用程序
一个项目是更早创建并成功运营的。现在,要创建一个应用程序,应用程序等同于项目的子模块。
在项目目录中创建一个应用程序:
$ python manage.py startapp民意调查
如果操作成功,您将在MySite文件夹下看到一个称为民意调查的文件夹。目录结构如下:
民意调查
t- __init__.py
.- admin.py
在移民
│_ _- __init__.py
s- models.py
。—— tests.py
s - 视图。
1个目录,6个文件
4.创建模型
每个Django模型都从django.db.models.model继承
模型中每个属性的每个属性代表数据库字段
通过Django模型API
在民意调查文件夹下打开Models.py文件。创建两个模型:
导入日期
来自django.db导入模型
来自django.utils重要时区
班级问题(Models.Model):
Question_Text = model.Charfield(max_length = 200)
pub_date = model.dateTimeField('Date已发布')
def was_publish_recression(seld):
返回self.pub_date = timezone.now()-dateTime.timedelta(天= 1)
班级选择(Models.Model):
问题=模型。Foreignkey(问题)
choce_text = models.charfield(max_length = 200)
投票= model.integerfield(默认= 0)
然后修改inporthed_apps以在mySite/settings.py中添加民意调查:
instasted_apps =((
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
“民意调查”,
治愈
添加新应用程序后,我们需要运行以下命令来告诉Django您的模型以进行更改。迁移数据库需要迁移:
$ python manage.py makemigrations民意调查
您将看到以下输出日志:
“民意调查”的迁移:
0001_Initial.py:
- 创建模型选择
- 创建模型问题
-DD现场问题选择
您可以从民意调查/迁移/0001_Initial.py查看迁移语句。
运行以下语句,您可以查看迁移SQL语句:
$ python manage.py sqlmigrate民意调查0001
输出结果:
开始;
创建表“ polls_choice”(“ id”整数而不是null主键自动启动,“ choice_text” varchar(200)而不是null,“投票” integer而不是null);
创建表“ polls_question”(“ id”整数而不是null主键自动启动,“ Question_Text” Varchar(200)不是null,“ pub_date” dateTime null)
插入“ polls_choice__new”(“ phoce_text”,“票”,“ id”)选择“ polls_choice”中的“ choice_text”,“票数”,“投票”,“ id”
丢弃表“ polls_choice”;
Alter Table“ Polls_Choice__new”重命名为“ Polls_Choice”;
在“ Polls_Choice”(“ Question_ID”)上创建索引Polls_choice_7aa0f6ee;
犯罪;
您可以运行以下命令以检查数据库是否存在问题:
$ python manage.py检查
再次运行以下命令以创建新添加的模型:
$ python manage.py迁移
执行操作:
应用所有迁移:管理员,内容类型,民意调查,auth,会议
运行迁移:
应用民意调查。0001_Initial...好的
总而言之,在修改模型时,您需要执行以下步骤:
修改型号.py文件
运行python manage.py makemigrations创建迁移语句
运行python manage.py迁移并迁移模型更改为数据库
您可以阅读django-admin.py文档以查看更多管理。
创建模型后,我们可以通过Django提供的API进行测试。run以下命令输入Python Shell的交互模式:
$ python manage.py shell
这是一些测试:
从polls.models导入问题,选择#导入我们刚刚编写的模型类。
#系统中还没有问题。
Question.Objects.all()
[]
#创建一个新问题。
#在默认设置文件中启用了对时区的支持,因此
#Django用tzinfo for pub_date来实现DateTime。使用timezone.now()
#而不是面团。dateTime.now(),它将做正确的事情。
来自django.utils重要时区
Q = Question(Question_text =“什么新功能?”,pub_date = timezone.now())
#将对象保存到数据库中。您必须明确调用Save()。
问:Save
#现在它有一个ID。请注意,这可能会说“ 1”的“ 1”,具体取决于
#您使用哪个数据库。那不是大事;这只是意味着你
#数据库后端喜欢返回整数作为Python长整数
#对象。
Q.ID
1
#通过Python属性访问模型字段值。
Q.question_text
“什么是新的?”
q.pub_date
dateTime.dateTime(2012,2,26,13,0,0,0,775217,tzinfo = utc)
#Change值通过更改属性,然后调用Save()。
q.question_text =“怎么了?”
问:Save
#Objects.all()显示数据库中的所有问题。
Question.Objects.all()
[问题:问题对象]
打印所有问题时,输出的结果是[问题:问题对象]。我们可以修改模型类以使其更容易理解。修改模型类:
来自django.db导入模型
班级问题(Models.Model):
#...
def __str __(self):#__unicode__ python 2
返回self.question_text
班级选择(Models.Model):
#...
def __str __(self):#__unicode__ python 2
返回self.choice_text
继续测试:
从民意调查。模型导入问题,选择
#确保我们的__str __()加法工作。
Question.Objects.all()
[问题:怎么了?]
#Django提供了一个富含数据库的查找API,该API完全由
#关键字参数。
Question.Objects.Filter(ID = 1)
[问题:怎么了?]
Question.Objects.Filter(Question_text_Startswith ='What')
[问题:怎么了?]
#获取今年提出的问题。
来自django.utils重要时区
curren_year = timezone.now()。年
Question.Objects.get(pub_date__year = current_year)
问题:怎么了?
#请求ID,这将引起例外。
Question.Objects.get(ID = 2)
Trackback(最近的最新电话):
Em
dotNotexist:不存在问题匹配查询。
#主键查找是最合并的情况,因此Django提供了一个
#主要钥匙精确查找的快捷方式。
#跟随者与Question.objects.get(ID = 1)相同。
Question.Objects.get(PK = 1)
问题:怎么了?
#确保我们的自定义方法有效。
Q = Question.Objects.get(PK = 1)
#给出一些选择。创建呼叫构造一个新的
#选择对象,执行插入语句,将选择添加到集合
可用选择的#并返回新选择对象。Django创建
#一套持有外国关系的“另一面”
#(例如,一个问题的选择)可以通过API访问。
Q = Question.Objects.get(PK = 1)
#从相关对象集中显示任何选择 - 到目前为止无。
q.choice_set.all()
[]
#创建三个选择。
Q.CHOICE_SET.CREATE(choce_text ='不多',票数= 0)
选择:不多
Q.CHOICE_SET.CREATE(choce_text ='the Sky',投票= 0)
选择:天空
c = q.choice_set.create(choce_text ='再次黑客入侵',票数= 0)
#选择对象可以访问其相关问题对象。
C.问题
问题:怎么了?
#和VICE,反之亦然:问题对象可以访问选择对象。
q.choice_set.all()
[选择:不是泥土,选择:天空,选择:再次入侵]
q.choice_set.count()
3
#API自动食品遵循您需要的相关船。
#使用面团下划线选择相关职位。
#这是您想要的深层层次的工作。没有限制。
#找到今年Pub_date的任何问题的所有选择
#(重用我们上面创建的“ Current_Year”变量)。
choce.objects.filter(问题__pub_date__year = current_year)
[选择:不是泥土,选择:天空,选择:再次入侵]
#让我们删除其中一个选择。为此使用delete()。
c = q.choice_set.filter(choce_text__startswith ='Just Hacking')
c.delete()
以上测试涉及与Django Orm相关的知识。有关详细信息,请参阅Django中的ORM。
5.管理管理员
Django具有构建-Django Admin背景管理接口的出色特征,对于管理人员而言,它很方便地添加和删除网站的内容。
新项目系统已为我们设置了背景管理功能。请参阅mySite/settings.py:
instasted_apps =((
'django.contrib.admin',#
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'我的网站',
治愈
同时,添加了进入背景管理的URL。您可以在MySite/urls.py中查看它:
url(r'^admin/',infulude(admin.site.urls)),#可以使用SET URL进入网站的背景
接下来,我们需要创建管理用户来登录到管理背景管理接口:
$ python manage.py createSuperuse
用户名(留空白以使用“六月”):管理员
电子邮件地址:
密码:
密码(再次):
超级用户成功创建了。
总结
最后,查看项目目录结构:
我的网站
Q - db.sqlite3
e- manage.py
t - 锰矿
│_ _- __init__.py
│e ─—设置.py
│u - urURLS.PY
│s-wsgi.py
S - 民意调查
│_ _- __init__.py
│d - 管理
│i - 移民
││├├─-0001_Initial.py
││├─..__Init__.py
│o - models.py
│e - ─-模板
民意调查
││├├─detail.html
││├ - index.html
thml
│e - tests.py
│u - urURLS.PY
│i - ─视图。
L ─—模板
在─管理员
_ - base_site.htm
通过上述介绍,我对Django的安装,操作以及如何创建视图以及如何创建视图和模型有了清晰的了解。接下来,您可以彻底了解Django的自动化测试,持久性,中间件和国际化的知识。
解决django“懒惰”的基本方法
现在,我们解决此问题的方法是“预载”。本质上,您要预先警告django orm,您必须一遍又一遍地告诉它相同的无聊指令。在上面的示例中,很容易添加此句子在DRF开始之前:
querySet = queryset.prefetch_reled('orders')
当DRF调用上述客户的相同序列化时,情况就是这样:
获取所有客户(执行两个回合数据库操作,第一个是获取客户,第二个是获得相关客户的所有相关顺序。)。
对于第一个客户,获取其订单(无需访问数据库,我们在上一步中获得了所需的数据)
对于第二个返回客户,获取订单(无需访问数据库)
对于第三个返回客户,获取订单(无需访问数据库)
对于第四个返回客户,获取订单(无需访问数据库)
对于第五返回客户,获取订单(无需访问数据库)
对于第六返回客户,获取订单(无需访问数据库)
您意识到您可以有很多客户,并且不再需要继续等待数据库。
实际上,在步骤1中请求Django Orm的“准备”,该步骤1可以在本地高速缓存数据中提供步骤2+所需的数据,并具有先前数据库,从本地缓存数据中读取数据基本上是瞬时的,因此我们有当我们有很多客户时,获得了巨大的性能加速。
解决Django REST框架的性能的标准化模式
我们已经确定了一种通用模式,可以优化Django REST框架的性能,也就是说,每当序列化查询嵌套字段时,我们添加了一个新的@StaticMethod,名为Setup_eager_loading,如下:
班级CobuliteRializer(Serializers.ModelSerializer):
orders = orderSerializer(许多= true,read_only = true)
def setup_eager_loading(cls,querySet):
“”“”执行不加载数据。“”“”“”“”“”“”
querySet = queryset.prefetch_reled('orders')
返回QuerySet
这样,无论您在何处使用此序列化,您只需要在调用serialization之前只调用setup_eager_loading,就像这样::
customer_qs = customer.objects.all()
customer_qs = cusiteerializer.setup_eager_loading(customer_qs)#设置急切的加载以避免n+1选择
post_data = cusiteerializer(customer_qs,多个= true).data。
或者,如果您有Apiview或Viewset,则可以在get_queryset方法中调用setup_eager_loading ::
def get_queryset(self):
querySet = cunituter.objects.all()
#设置急切的加载以避免n+1选择
querySet = self.get_serializer_class()。setup_eager_loading(querySet)
返回QuerySet
在上面的所有示例中,我们构造的过滤器仅将字段值与一定常数进行比较。如果我们想比较两个字段的值,我们该怎么办?
Django提供了F()来进行此类比较。f()实例可以参考查询中的字段,以比较同一模型实例中两个不同字段的值。
Django支持F()对象与F()对象和常数之间加法,减法,乘法和成型的操作。
关键字参数查询(例如Filter()和其他方法是“和”的方法。如果您需要执行更复杂的查询(例如或语句),则可以使用Q对象。
来自django.db.models导入Q
Q(标题__startswith ='py')
Q可以与|结合使用Q对象。操作符号。当操作员在两个Q对象上使用时,它会产生一个新的Q对象。
查询名称称为水保证金或价格大于100的书
您可以组合并|括号并使用括号进行分组来编写任何复杂的Q对象。在同一时间,可以使用Q对象?运算符被逆转,从而使组合可以正常查询和抗抗 - (非)查询:
查询函数可以与Q对象和关键字参数混合。提供给查询函数的所有参数(关键字参数或Q对象)为“和”。但是,如果出现Q对象,则必须在所有关键字参数的前面。例如:
查询名称,称为水利润,价格大于100
结论:以上是首席CTO注释的全部内容,每个人都为如何求解Django惯性查询。感谢您阅读本网站的内容。我希望这对您有帮助。不要忘记在此网站上找到它。