18๐
How nonlocal
works
If you use nonlocal
, that means that Python will, at the start of the function, look for a variable with the same name from one scope above (and beyond). But here you did not define such one. We can fix it with defining one, one level higher:
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)
You can use global
in which case you do not need to declare such variable (in that case it is declared at the upper level), but this is actually an anti-pattern as well.
Efficient database querying in Django ORM
Nevertheless the way you perform the filtering here, will usually be quite inefficient: you here first iterate over all Topic
s, then for each topic, you do an extra query fetching all Entry
s, then for each Entry
you fetch all Tag
s, and then you look whether one of the tags is #log
. Now imagine that you have 10 topics, that have 10 entries per topic, and 5 tags per entry. That results in 500+ queries you do at the database level. We can construct a filter like:
topics_with_log_tag = Topics.objects.filter(entry__tags__contains='#log').distinct()
or more readable (brackets are used to allow multi-line expressions):
topics_with_log_tag = (Topics.objects
.filter(entry__tags__contains='#log')
.distinct())
Note that the above will (just like your code did), also contains topics with as tags
for example '#logarithm'
. It only checks if it contains a certain substring. In order to prevent that, you will need more advanced filtering, or better tag representation (with an end marker).
For example if every topic ends with a comma (like '#foo,#bar,'
) then we could query for '#log,'
.
We can also work with regular expressions and check for a new hash character, or the end of the string.
5๐
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)
you can only nonlocal the local variables not global variables
- Disabling Django CSRF for views that do not always have a response
- Appropriate choice of authentication class for python REST API used by web app
- How to debug: Internal Error current transaction is aborted, commands ignored until end of transaction block
- Django: WSGIRequest' object has no attribute 'user' on some pages?
- How to add an initial/default value using Django Filters?