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".
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
.filter
following my list order.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
")