How to assign and manage a priority mechanism

Viewed 375

I am working on a Django web application where users create a list of tasks. Each task is a record in the database (ie: a Django object) and the user is able to assign each task a priority.

If the user creates 10 tasks, each of them would have a priority from 1 to 10. I'm struggling to figure out an efficient way to allow users to change the priority of tasks as well as insert and delete tasks. For example:

  • A user moves task priority 3 down to 7. The other tasks priorities need to be adjusted accordingly.
  • A user deletes task with priority 4. Once again the remaining tasks priorities would need to be adjusted.
  • A user inserts a new task with priority 5. This means the existing tasks from priority 5 onwards need to be shifted.

Are there any design patterns or suggestions on how to manage what essentially amounts to a queue based on the priority of each item while allowing users to:

  • Move tasks up and down the priority list
  • Delete tasks
  • Add new tasks with specified priorities.
3 Answers

Why are you working so hard to build queues? Can't you just use .order_by

Assume this is your model:

class Task(models.Model):
    user = models.ForeignKey(User)
    priority = models.IntegerField()
    created = models.DateTimeField(auto_now=True)

Then when you need a list of all tasks for a user you can just do

qs = Task.objects.filter(user=your_user_instance).order_by('-priority', 'created')

Now the variable qs is an iterator that lists the highest priority tasks first (And if two tasks have the same priority it'll list the older one first)

Here is how i solved the above case for me

task_order_list = self.request.POST.get("task_order_list",'[]')
task_order_list = json.loads(task_order_list)

task_qs = Task.objects.all()
for priority,id in enumerate(task_order_list):
    task_qs.filter(id=id).update(priority=priority)

for the above snippet, suppose :

Actual list of task id's : [1,2,3,4,5]

Input :

New list : [5,3,2,4,1]

Output :

updated list : [5,3,2,4,1]

You don't have to assign numbers to the priority. You can just use strings that have in theory infinite resolution.

item      index
-----------------
gizmo     1
              <<------ Oh no! no room between 1 and 2.
                       This requires incrementing _every_ item after it
gadget    2
gear      3
toolkit   4
box       5

But here if you count by 100s:

item      index
-----------------
gizmo     100
              <<------ Sweet :). I can re-order 99 (!) items here
                       without having to change anything else
gadget    200
gear      300
toolkit   400
box       500

Even better: here is how Jira solves this problem. Their "rank" (what you call index) is a string value that allows a ton of breathing room in between ranked items.

Here is a real example of a jira database I work with

   id    | jira_rank
---------+------------
 AP-2405 | 0|hzztxk:
 ES-213  | 0|hzztxs:
 AP-2660 | 0|hzztzc:
 AP-2688 | 0|hzztzk:
 AP-2643 | 0|hzztzs:
 AP-2208 | 0|hzztzw:
 AP-2700 | 0|hzztzy:
 AP-2702 | 0|hzztzz:
 AP-2411 | 0|hzztzz:i
 AP-2440 | 0|hzztzz:r

Notice this example hzztzz:i. The advantage of a string rank is that you run out of room between two items, you still don't have to re-rank anything else. You just start appending more characters to the string to narrow down focus. Based on the answer from here

Although saying all that this package that is fairly used, actually uses a positive integer and issues SQL to update all the following order numbers.

Related