Как создать пользовательский сериализатор для DRF APIView для получения списка записей вместо идентификаторов
Я создаю API для программы маркировки картинок. Картинка (ресурс) может иметь метки или verified_labels - если более одного пользователя ввели метку для одного и того же ресурса. Я пытаюсь расширить программу, добавив ввод табу. Табу означает, что эти метки были введены наиболее часто для определенного ресурса.
В настоящее время моими моделями являются Resource, Label и VerifiedLabel.
models.py
class Resource(models.Model):
id = models.PositiveIntegerField(null=False, primary_key=True)
hash_id = models.CharField(max_length=256)
creators = models.ManyToManyField(Creator)
titles = models.ManyToManyField(Title)
created_start = models.DateField(null=True)
created_end = models.DateField(null=True)
location = models.CharField(max_length=512, null=True)
institution_source = models.CharField(max_length=512, blank=True)
institution = models.CharField(max_length=512, blank=True)
origin = models.URLField(max_length=256, null=True)
enabled = models.BooleanField(default=True)
media_type = models.CharField(max_length=256, default='picture')
objects = models.Manager()
def __str__(self):
return self.hash_id or ''
@property
def verified_labels(self):
verified_labels = self.labels.values('verified_label').annotate(count=Count('label'))
return verified_labels.values('verified_label_id', 'verified_label__name', 'verified_label__language', 'count')
class VerifiedLabel(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
return self.name or ''
class Label(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE)
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, related_name='labels')
verified_label = models.ForeignKey(VerifiedLabel, on_delete=models.CASCADE)
created = models.DateTimeField(editable=False)
score = models.PositiveIntegerField(default=0)
origin = models.URLField(max_length=256, blank=True, default='')
objects = models.Manager()
def __str__(self):
return str(self.verified_label) or ''
def save(self, *args, **kwargs):
if not self.id:
self.created = timezone.now()
return super().save(*args, **kwargs)
У меня есть сериализатор для каждой модели, но для представления я использую этот сериализатор, который в основном сериализует объект ресурса и извлекает taboo_labels для этого объекта.
Моя основная проблема заключается в том, что вместо Label происходит обращение к VerifiedLabel, а мне нужно отсортировать наиболее используемые метки. В таблице VerifiedLabel все имена уникальны, поэтому я не могу отсортировать наиболее используемые.
serializers.py
class TabooLabelSerializer(serializers.ModelSerializer):
creators = CreatorSerializer(many=True)
titles = TitleSerializer(many=True)
taboo_labels = serializers.SerializerMethodField('get_taboo_tags')
class Meta:
model = Resource
fields = ['id', 'hash_id', 'titles', 'creators', 'taboo_labels']
read_only_fields = ['titles', 'creators', 'institution']
def get_taboo_labels(self, res):
"""
:param res:
:return: A list of the most used labels per Resource
"""
# TODO: Filter out most used labels and return text instead of id
taboo_labels = res.tags.values_list('tag', flat=True)
return taboo_labels
def to_representation(self, data):
data = super().to_representation(data)
return data
Моя вторая проблема заключается в том, что я хочу, чтобы в объекте JSON в браузере возвращался текст, а не идентификаторы.
views.py
class GameResourceView(APIView):
"""
API view to handle resources
"""
serializer_class = TabooLabelSerializer
def get_queryset(self):
resource = None
random_resource_idx = None
while resource is None:
while resource is None:
while random_resource_idx is None:
while not Resource.objects.all().filter(id=random_resource_idx).exists():
random_number = random.randint(0, Resource.objects.count() - 1)
if not Resource.objects.all().filter(id=random_number).exists():
random_number_alternative = random.randint(0, Resource.objects.count() - 1)
if Resource.objects.all().filter(id=random_number_alternative).exists():
random_resource_idx = random_number_alternative
else:
random_resource_idx = random_number
resource = Resource.objects.all().filter(id=random_resource_idx)
return resource
def get(self, request, *args, **kwargs):
resource = self.get_queryset()
serializer = TabooLabelSerializer(resource, many=True)
return Response({
'resource and labels': serializer.data
})
В основном я хочу следующее:
{
"resource and labels to combine": [
{
"some resource data "
}
],
"taboo_labels": [
'boat',
'horse',
'lake'
]
}
]
}
и то, что я получаю в настоящее время это:
{
"resource and labels to combine": [
{
"some resource data "
}
],
"taboo_labels": [
62,
195,
133
]
}
]
}