[damned-lies] Use the new UNION capability of the Django 1.11 ORM
- From: Claude Paroz <claudep src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [damned-lies] Use the new UNION capability of the Django 1.11 ORM
- Date: Wed, 5 Apr 2017 09:22:57 +0000 (UTC)
commit bcab396142414d39f4c04829ec8291e225479b03
Author: Claude Paroz <claude 2xlibre net>
Date: Wed Apr 5 11:22:22 2017 +0200
Use the new UNION capability of the Django 1.11 ORM
common/utils.py | 122 +----------------------------------------------------
vertimus/feeds.py | 30 ++++++-------
2 files changed, 15 insertions(+), 137 deletions(-)
---
diff --git a/common/utils.py b/common/utils.py
index 13cd504..7c75383 100644
--- a/common/utils.py
+++ b/common/utils.py
@@ -1,4 +1,3 @@
-import operator
from django.conf import settings
from django.utils.translation import ugettext as _, get_language
from languages.models import Language
@@ -23,137 +22,20 @@ def lc_sorted(*args, **kwargs):
kwargs['key'] = lambda x: collator.getSortKey(key(x))
return sorted(*args, **kwargs)
+
def trans_sort_object_list(lst, tr_field):
"""Sort an object list with translated_name"""
for l in lst:
l.translated_name = _(getattr(l, tr_field))
return lc_sorted(lst, key=lambda o: o.translated_name.lower())
-def merge_sorted_by_field(object_list1, object_list2, field):
- """
- Each call returns the next item, sorted by field in ascending order or in
- descending order if the field name begins by a minus sign.
-
- >>> from datetime import datetime
- >>> import itertools
- >>> class Foo(object):
- ... def __init__(self, num):
- ... self.num = num
- ... def __repr__(self):
- ... return str(self.num)
- ...
- >>> l1 = (Foo(1), Foo(8), Foo(5))
- >>> l2 = (Foo(1), Foo(2), Foo(4), Foo(4), Foo(6))
- >>> merge_sorted_by_field(l1, l2, 'num')
- [1, 1, 2, 4, 4, 5, 6, 8]
- >>> merge_sorted_by_field(l1, l2, 'num')[:3]
- [1, 1, 2]
- >>> l1 = (Foo(3), Foo(9), Foo(5))
- >>> l2 = (Foo(6), Foo(4), Foo(4), Foo(2), Foo(1))
- >>> [el.num for el in merge_sorted_by_field(l1, l2, '-num')]
- [9, 6, 5, 4, 4, 3, 2, 1]
- """
- import itertools
- if field is not None and field[0] == '-':
- # Reverse the sort order
- field = field[1:]
- reverse = True
- else:
- reverse = False
-
- return sorted(itertools.chain(object_list1, object_list2),
- key=lambda x: getattr(x, field),
- reverse=reverse)
-
-def imerge_sorted_by_field(object_list1, object_list2, field):
- """
- Each call returns the next item, sorted by field in ascending order or in
- descending order if the field name begins by a minus sign.
-
- This function is faster (only one comparison by iteration) and uses less
- memory than merge_sorted_by_field (iterator) but the lists of objects must
- be already sorted in the same order as field.
-
- >>> from datetime import datetime
- >>> import itertools
- >>> class Foo(object):
- ... def __init__(self, num):
- ... self.num = num
- ... def __repr__(self):
- ... return str(self.num)
- ...
- >>> l1 = (Foo(1), Foo(3), Foo(5))
- >>> l2 = (Foo(1), Foo(2), Foo(4), Foo(6), Foo(8))
- >>> [el.num for el in imerge_sorted_by_field(l1, l2, 'num')]
- [1, 1, 2, 3, 4, 5, 6, 8]
- >>> [el.num for el in itertools.islice(imerge_sorted_by_field(l1, l2, 'num'), 3)]
- [1, 1, 2]
- >>> l1 = []
- >>> [el.num for el in imerge_sorted_by_field(l1, l2, 'num')]
- [1, 2, 4, 6, 8]
- >>> l1 = (Foo(5), Foo(4), Foo(1))
- >>> l2 = (Foo(6), Foo(4), Foo(4), Foo(2), Foo(1))
- >>> [el.num for el in imerge_sorted_by_field(l1, l2, '-num')]
- [6, 5, 4, 4, 4, 2, 1, 1]
- """
- if field is not None and field[0] == '-':
- # Reverse the sort order
- field = field[1:]
- op = operator.gt
- else:
- op = operator.lt
-
- iter1, iter2 = iter(object_list1), iter(object_list2)
-
- # Too many try/except couples to my taste but I don't know how to filter the
- # StopIteration to find the source.
-
- try:
- el1 = next(iter1)
- except StopIteration:
- # Finish the other list
- while True:
- el2 = next(iter2)
- yield el2
-
- try:
- el2 = next(iter2)
- except StopIteration:
- # Finish the other list
- while True:
- # el1 is already fetched
- yield el1
- el1 = next(iter1)
-
- while True:
- if op(getattr(el1, field), getattr(el2, field)):
- yield el1
- try:
- el1 = next(iter1)
- except StopIteration:
- # Finish the other list
- while True:
- yield el2
- el2 = next(iter2)
- else:
- yield el2
- try:
- el2 = next(iter2)
- except StopIteration:
- # Finish the other list
- while True:
- yield el1
- el1 = next(iter1)
def is_site_admin(user):
return user.is_superuser or settings.ADMIN_GROUP in [g.name for g in user.groups.all()]
+
def get_user_locale(request):
curlang = Language.get_language_from_ianacode(request.LANGUAGE_CODE)
if curlang and curlang.locale == 'en':
curlang = None
return curlang
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
diff --git a/vertimus/feeds.py b/vertimus/feeds.py
index 7d27a44..e199123 100644
--- a/vertimus/feeds.py
+++ b/vertimus/feeds.py
@@ -1,12 +1,12 @@
-from itertools import islice
from django.core import urlresolvers
+from django.contrib.sites.models import Site
from django.contrib.syndication.views import Feed, FeedDoesNotExist
from django.utils.translation import ugettext_lazy as _
-from django.contrib.sites.models import Site
+
from languages.models import Language
from teams.models import Team
from vertimus.models import Action, ActionArchived
-from common.utils import imerge_sorted_by_field
+
class LatestActionsByLanguage(Feed):
title_template = 'feeds/actions_title.html'
@@ -29,13 +29,11 @@ class LatestActionsByLanguage(Feed):
return _("Latest actions of the GNOME Translation Project for the %s language") % obj.name
def items(self, obj):
- # The Django ORM doesn't provide the UNION SQL feature :-(
- # so we need to fetch twice more objects than required
- actions =
Action.objects.filter(state_db__language=obj.id).select_related('state_db').order_by('-created')[:20]
- archived_actions =
ActionArchived.objects.filter(state_db__language=obj.id).select_related('state_db').order_by('-created')[:20]
-
- # islice avoid to fetch too many objects
- return islice(imerge_sorted_by_field(actions, archived_actions, '-created'), 20)
+ actions = Action.objects.filter(state_db__language=obj.id).select_related('state_db'
+ ).union(
+
ActionArchived.objects.filter(state_db__language=obj.id).defer('sequence').select_related('state_db')
+ )
+ return actions.order_by('-created')[:20]
def item_link(self, item):
link = urlresolvers.reverse('vertimus_by_names',
@@ -73,13 +71,11 @@ class LatestActionsByTeam(Feed):
return _("Latest actions made by the %s team of the GNOME Translation Project") % obj
def items(self, obj):
- # The Django ORM doesn't provide the UNION SQL feature :-(
- # so we need to fetch twice more objects than required
- actions =
Action.objects.filter(state_db__language__team=obj.id).select_related('state_db').order_by('-created')[:20]
- archived_actions =
ActionArchived.objects.filter(state_db__language__team=obj.id).select_related('state_db').order_by('-created')[:20]
-
- # islice avoid to fetch too many objects
- return islice(imerge_sorted_by_field(actions, archived_actions, '-created'), 20)
+ actions = Action.objects.filter(state_db__language__team=obj.id).select_related('state_db'
+ ).union(
+
ActionArchived.objects.filter(state_db__language__team=obj.id).defer('sequence').select_related('state_db')
+ )
+ return actions.order_by('-created')[:20]
def item_link(self, item):
link = urlresolvers.reverse('vertimus_by_names',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]