Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions tof/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
# @Date: 2019-11-17 15:02:55
# @Last Modified by: MaxST
# @Last Modified time: 2019-11-19 16:40:49
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import get_language
from django.db.models import Case, When, Exists, F, OuterRef, Subquery
from django.db import models

from .decorators import tof_filter, tof_prefetch
Expand All @@ -21,6 +24,38 @@ def exclude(self, *args, **kwargs):
def get(self, *args, **kwargs):
return super().get(*args, **kwargs)

@tof_filter # noqa
def order_by(self, *args):
from .models import Translation

content_type = ContentType.objects.get_for_model(self.model)

new_args = []
for arg in args:
field_name, order = arg, ''
if arg.startswith('-') or arg.startswith('+'):
field_name, order = arg[1:], arg[0]

if field_name == '?':
new_args.append('?')
continue

new_args.append(f'{order}_{field_name}')

translation = Translation.objects.filter(content_type=content_type, lang=get_language(),
field__name=field_name)

self = self.annotate(**{f'_{field_name}': Case(
When(
Exists(translation.filter(object_id=OuterRef('pk'))),
then=Subquery(translation.filter(object_id=OuterRef('pk')).values('value'))
),
default=F(field_name),
output_field=models.CharField(),
)})

return super().order_by(*new_args)


class TranslationsQuerySet(DecoratedMixIn, models.QuerySet):
pass
Expand Down
89 changes: 89 additions & 0 deletions tof/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,95 @@ def test_behavior(self):
self.assertEqual(wine1, serch_wine)


class OrderByTestCase(TestCase):
@classmethod
def setUpTestData(cls):
clean_model(Wine)

cls.wine1 = mixer.blend(Wine, title='Wine 1', temperature_from=10)
cls.wine2 = mixer.blend(Wine, title='Wine 2', temperature_from=20)

ct = ContentType.objects.get_for_model(Wine)
fld = mixer.blend(TranslatableField, name='title', title='title', content_type=ct)
fld2 = mixer.blend(TranslatableField, name='description', title='description', content_type=ct)

lang_en = Language.objects.get(iso='en')

mixer.blend(Translation, content_object=cls.wine1, field=fld, lang=lang_en, value='Wine 1 title')
mixer.blend(Translation, content_object=cls.wine1, field=fld2, lang=lang_en, value='Wine 2 desc')

mixer.blend(Translation, content_object=cls.wine2, field=fld, lang=lang_en, value='Wine 2 title')
mixer.blend(Translation, content_object=cls.wine2, field=fld2, lang=lang_en, value='Wine 2 desc')

def test_order_by_one_field_asc(self):
ordered_wines = [wine for wine in Wine.objects.order_by('title')]
expected_ordered_wines = [self.wine1, self.wine2]

self.assertEqual(ordered_wines, expected_ordered_wines)

ordered_wines = [wine for wine in Wine.objects.order_by('description')]
expected_ordered_wines = [self.wine1, self.wine2]

self.assertEqual(ordered_wines, expected_ordered_wines)

def test_order_by_one_field_desc(self):
ordered_wines = [wine for wine in Wine.objects.order_by('-title')]
expected_ordered_wines = [self.wine2, self.wine1]

self.assertEqual(ordered_wines, expected_ordered_wines)

ordered_wines = [wine for wine in Wine.objects.order_by('-description')]
expected_ordered_wines = [self.wine1, self.wine2]

self.assertEqual(ordered_wines, expected_ordered_wines)

def test_order_by_two_fields_asc(self):
ordered_wines = [wine for wine in Wine.objects.order_by('description', 'title')]
expected_ordered_wines = [self.wine1, self.wine2]

self.assertEqual(ordered_wines, expected_ordered_wines)

ordered_wines = [wine for wine in Wine.objects.order_by('-description', 'title')]
expected_ordered_wines = [self.wine1, self.wine2]

self.assertEqual(ordered_wines, expected_ordered_wines)

def test_order_by_two_fields_desc(self):
ordered_wines = [wine for wine in Wine.objects.order_by('-description', '-title')]
expected_ordered_wines = [self.wine2, self.wine1]

self.assertEqual(ordered_wines , expected_ordered_wines)

ordered_wines = [wine for wine in Wine.objects.order_by('description', '-title')]
expected_ordered_wines = [self.wine2, self.wine1]

self.assertEqual(ordered_wines, expected_ordered_wines)

def test_order_by_random(self):
ordered_wines = [wine for wine in Wine.objects.order_by('?')]
expected_ordered_wines_1 = [self.wine1, self.wine2]
expected_ordered_wines_2 = [self.wine2, self.wine1]

self.assertTrue(ordered_wines == expected_ordered_wines_1 or ordered_wines == expected_ordered_wines_2)

def test_order_by_two_order_by(self):
ordered_wines = [wine for wine in Wine.objects.order_by('title').order_by('description')]
expected_ordered_wines = [self.wine1, self.wine2]

self.assertEqual(ordered_wines, expected_ordered_wines)

ordered_wines = [wine for wine in Wine.objects.order_by('description').order_by('title')]
expected_ordered_wines = [self.wine1, self.wine2]

self.assertEqual(ordered_wines, expected_ordered_wines)

def test_order_by_with_no_translatable_field(self):
ordered_wines = [wine for wine in Wine.objects.order_by('-temperature_from', 'title')]
expected_ordered_wines = [self.wine2, self.wine1]

self.assertEqual(ordered_wines, expected_ordered_wines)


class TranslatableTextTestCase(TestCase):
@classmethod
def setUpTestData(cls):
Expand Down