Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Imports 

2 

3from django.conf import settings 

4from django.db import models 

5from django.db.models import F 

6from django.utils.translation import ugettext_lazy as _ 

7 

8# Exports 

9 

10__all__ = ( 

11 "SortedModel", 

12) 

13 

14# Constants 

15 

16AUTH_USER_MODEL = settings.AUTH_USER_MODEL 

17 

18# Models 

19 

20 

21class SortedModel(models.Model): 

22 """Allow a model to be easily sortable. 

23 

24 **Fields** 

25 

26 - ``sort_order`` 

27 

28 **Implementation** 

29 

30 .. code-block:: python 

31 

32 from superdjango.db.sorted.models import SortedModel 

33 

34 class Task(SortedModel): 

35 # ... 

36 class Meta: 

37 ordering = ["sort_order"] 

38 

39 """ 

40 

41 sort_order = models.IntegerField( 

42 _("sort order"), 

43 default=1, 

44 help_text=_("How the record should be sorted.") 

45 ) 

46 

47 class Meta: 

48 abstract = True 

49 

50 # noinspection PyUnusedLocal 

51 @staticmethod 

52 def pre_save_sort_order(sender, instance, **kwargs): 

53 """Insure that the ``sort_order`` has a value. 

54 

55 .. code-block:: python 

56 

57 from django.db.models.signals import pre_save 

58 from .models import Task 

59 

60 pre_save.connect( 

61 Task.pre_save_sort_order, 

62 Task, 

63 dispatch_uid="task_pre_save_sort_order" 

64 ) 

65 

66 """ 

67 if not instance.sort_order or instance.sort_order == 0: 

68 try: 

69 # Get the previous sort order. 

70 last = sender.objects.values("sort_order").order_by('-%s' % "sort_order")[0] 

71 instance.sort_order = last["sort_order"] + 1 

72 except IndexError: 

73 # Set the sort order to 1 if this is the first record. 

74 instance.sort_order = 1 

75 

76 def update_sort_order(self, sort_order, commit=True): 

77 """Move the record to a different position, shifting the other records around it. 

78 

79 :param sort_order: The new position. 

80 :type sort_order: int 

81 

82 :param commit: Indicates whether to save the record after the move. 

83 :type commit: bool 

84 

85 """ 

86 

87 # Force the new position to be an integer. This ensures the method works when interacting with a web-based API. 

88 new_position = int(sort_order) 

89 

90 # The default position is always 1. 

91 original_position = self.sort_order 

92 

93 # There's nothing to do if the new position isn't actually different. 

94 if new_position == original_position: 

95 return 

96 

97 # Prepare to move other records out of the way. 

98 # noinspection PyTypeChecker 

99 if new_position < original_position: 

100 shift_amount = 1 

101 # noinspection PyTypeChecker 

102 select_range = (new_position, original_position - 1) 

103 else: 

104 shift_amount = -1 

105 # noinspection PyTypeChecker 

106 select_range = (original_position + 1, new_position) 

107 

108 # Shorten the statements by getting the class here. 

109 cls = self.__class__ 

110 

111 # Update records. 

112 criteria = { 

113 'sort_order__range': select_range, 

114 } 

115 

116 # noinspection PyUnresolvedReferences 

117 qs = cls.objects.filter(**criteria) 

118 

119 for row in qs: 

120 row.update(field=F("sort_order") + shift_amount) 

121 

122 # Save the new position. 

123 self.sort_order = new_position 

124 

125 if commit: 

126 # noinspection PyUnresolvedReferences 

127 self.save()