我想通过指定的' log'来获取主题。标记:
在嵌套函数get_topics_with_log_tag
中,我设置变量topics_with_log_tag
非本地:
def log(request):
"""Show all topics and entries with log tags"""
topics = Topic.objects.all()
#select entries with log tag
def get_topics_with_log_tag(topics):
nonlocal topics_with_log_tag
topics_with_log_tag = []
for topic in topics:
for entry in topic.entry_set.all():
if "#log" in entry.tags:
topics_with_log_tag.append(topic)
get_topics_with_log_tag(topics)
抛出SyntaxError:
SyntaxError: no binding for nonlocal 'topics_with_log_tag' found
实际上,我确实绑定了它topics_with_log_tag = []
以上代码可以以多余的方式重写为
topics = Topic.objects.all()
#select entries with log tag
def get_topics_with_log_tag(topics):
# nonlocal topics_with_log_tag
topics_with_log_tag = []
for topic in topics:
for entry in topic.entry_set.all():
if "#log" in entry.tags:
topics_with_log_tag.append(topic)
return topics_with_log_tag
topics_with_log_tag = get_topics_with_log_tag(topics)
使用nonlocal
的问题是什么?
我发现了错误。
Willem Van Onsem引入了数据库级过滤器,而不是嵌套的for循环。
models.py
class Topic(models.Model):
"""A topic the user is learning about."""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User)
def __str__(self):
"""Return a string representation of the model."""
return self.text
class Entry(models.Model):
"""Something specific learned about a topic"""
topic = models.ForeignKey(Topic)
title = models.CharField(max_length=200)
text = models.TextField()
tags = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
答案 0 :(得分:2)
nonlocal
如何运作如果使用nonlocal
,这意味着Python将在函数开始时从上面(及更高)的一个范围中查找具有相同名称的变量。但在这里你没有定义这样的。我们可以通过定义一个更高的级别来修复它:
def log(request):
"""Show all topics and entries with log tags"""
topics = Topic.objects.all()
#select entries with log tag
topics_with_log_tag = []
def get_topics_with_log_tag(topics):
nonlocal topics_with_log_tag
topics_with_log_tag = []
for topic in topics:
for entry in topic.entry_set.all():
if "#log" in entry.tags:
topics_with_log_tag.append(topic)
get_topics_with_log_tag(topics)
你可以使用global
在这种情况下你不需要声明这样的变量(在这种情况下它是在上层声明的),但这实际上也是一个反模式。
然而,你在这里执行过滤的方式通常效率很低:你首先迭代所有Topic
,然后对于每个主题,你做一个额外的查询来获取所有Entry
,然后,对于每个Entry
,您获取所有Tag
,然后查看其中一个标记是#log
。现在假设您有10个主题,每个主题有10个条目,每个条目有5个标签。这导致您在数据库级别执行500多个查询。我们可以构建一个过滤器,如:
topics_with_log_tag = Topics.objects.filter(entry__tags__contains='#log').distinct()
或更具可读性(括号用于允许多行表达式):
topics_with_log_tag = (Topics.objects
.filter(entry__tags__contains='#log')
.distinct())
请注意,上述内容(就像您的代码所做的那样),还包含tags
为'#logarithm'
的主题,例如'#foo,#bar,'
。它只检查它是否包含某个子字符串。为了防止这种情况,您需要更高级的过滤或更好的标记表示(带有结束标记)。
例如,如果每个主题都以逗号结尾(例如'#log,'
),那么我们可以查询development.rb
。
我们也可以使用正则表达式并检查新的哈希字符或字符串的结尾。
答案 1 :(得分:2)
def log(request):
"""Show all topics and entries with log tags"""
topics_with_log_tag=[]
topics = Topic.objects.all()
#select entries with log tag
def get_topics_with_log_tag(topics):
nonlocal topics_with_log_tag
topics_with_log_tag = []
for topic in topics:
for entry in topic.entry_set.all():
if "#log" in entry.tags:
topics_with_log_tag.append(topic)
get_topics_with_log_tag(topics)
你只能非局部的局部变量而不是全局变量