1

first of all, I'm not a native at ENG so plz be patient my ENG skills or give me some advice.

(FYI, Django ver 3.2.9 & DRF ver 3.12.4 with postgres ver 12.7)

I'm writing API creating a post by using drf serializer. And I've been facing a problem with "the order of tags adding to the post".

  • post and tag models are connected through M2M field

which means, let's say I add tags a, b, and c on a post. The logic I use as follows.

# class Serializer
# def create(instance):
# instance : specific post instance

tags = ['t', 'a', 'g', 's']
Tag.objects.bulk_create([Tag(name = tag) for tag in tags])
instance.tags.add(*[tag for tag in Tag.objects.filter(name__in = tags)])

run this at first. tags are added in this order

TagQuerySet[Tag<'t'>, Tag<'a'>, Tag<'g'>, Tag<'s'>]

And my API takes the other create request that include the tags of the existing like,

tags = ['g', 'a', 's']

django add in the sorted order, not in the order I want like,

# tags new created instance
TagQuerySet[Tag<'a'>, Tag<'g'>, Tag<'s'>]

I know the method that adding tags following my list order using for loop

for tag in tags:
    instance.tags.add(Tag.objects.get(name=tag))

but it's not efficient.

So my question is

  • how to get queryset using .filter following my list order.
  • If there is no way for this. What is the efficient way for adding tags to post
SeojunYoun
  • 15
  • 5

1 Answers1

1

You can add another column to Tag class namely priority and whenever you insert rows add the priority of the value.

You can then order by priority something like this:

tags = [('t', 4), ('a', 2), ('g', 1), ('s', 3)]
Tag.objects.bulk_create([Tag(name = tag[0], priority=tag[1]) for tag in tags])

Tag.objects.all().order_by('priority')

also the the optimized version of this:

for tag in tags:
    instance.tags.add(Tag.objects.get(name=tag))

is this:

tags_db = Tag.objects.filter(name__in=[tag for tag in tags])
instance.tags.set(list(tags_db))

Edit:

Sorting using python:

my_order_list = ['g', 'a', 's', 't']
sorted(Tag.objects.all(), key=lambda x: my_order_list.index(x.name))

Sorting using sql case expressions:

Tag.objects.raw("
   SELECT * FROM Tag ORDER BY 
       CASE name
         WHEN 'g' THEN 1
         WHEN 'a' THEN 2
         WHEN 's' THEN 3
         ELSE 4 
       END
")
Ahtisham
  • 9,170
  • 4
  • 43
  • 57