Как скоординировать случайно выбранные объекты в DRF APIView?

Я создаю API для игры и мне нужно выбрать случайный раунд игры для случайно выбранного ресурса.

Выбор случайного ресурса работает. То, что я пытаюсь сделать сейчас, для координации игроков, это отфильтровать раунды игры по ресурсу, который был выбран случайным образом, и затем вернуть случайный раунд игры.

Ниже представлен код, который я пробовал до сих пор, а именно доступ к ресурсу, для которого был сыгран раунд игры, через метод с декоратором @property.

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 tags(self):
        tags = self.taggings.values('tag').annotate(count=Count('tag'))

        return tags.values('tag_id', 'tag__name', 'tag__language', 'count')


class Gameround(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
    gamesession = models.ForeignKey(Gamesession, on_delete=models.CASCADE)
    created = models.DateTimeField(editable=False)
    score = models.PositiveIntegerField(default=0)

    objects = models.Manager()

    def save(self, *args, **kwargs):
        if not self.id:
            self.created = timezone.now()

        return super().save(*args, **kwargs)

    def create(self):
        pass

    @property
    def tags(self):
        tags = self.taggings.values('tag')

        return tags.values('tag_id', 'tag__name', 'tag__language', 'resource_id')

class Tagging(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
    gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, related_name='taggings')
    resource = models.ForeignKey(Resource, on_delete=models.CASCADE, related_name='taggings')
    tag = models.ForeignKey(Tag, 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 create(self, tag):
        tagging = self.create(tag=tag)

    def __str__(self):
        return str(self.tag) or ''

    def save(self, *args, **kwargs):
        if not self.id:
            self.created = timezone.now()

        return super().save(*args, **kwargs)

Затем я сериализую игровой раунд следующим образом:

*serializers.py

class GameroundSerializer(serializers.ModelSerializer):
  gamesession = GamesessionSerializer(read_only=True)
  user = CustomUserSerializer(read_only=True)
  tags_to_compare = serializers.SerializerMethodField('get_tags_to_compare')

  class Meta:
    model = Gameround
    fields = ['id', 'user', 'gamesession', 'created', 'score', 'tags_to_compare']

  def get_tags_to_compare(self, round):
    taggings = round.tags
    return taggings

  def to_representation(self, data):
    data = super().to_representation(data)
    return data

В представлении у меня есть запрос get, который сначала выбирает случайный ресурс, затем я пытаюсь отфильтровать раунды игры, чтобы включить только те, в которых участвовал этот ресурс, а затем я пытаюсь получить случайный раунд игры.

views.py

class GameroundView(APIView):
    """
    API endpoint for game rounds
    """

    def get(self, request, *args, **kwargs):
        controller = GameViewController()
        random_resource = controller.get_resource()
        gameround = Gameround.objects.all().filter(taggings__resource_id=random_resource).order_by("?").first()
        gameround_serializer = GameroundSerializer(gameround)
        return Response(gameround_serializer.data)

Похоже, что это не работает, поскольку я продолжаю получать ошибку "The response content must be rendered before iterated over iterated"

Я также попробовал создать переменную id и передать ее в качестве resource_id следующим образом:

# id of the random Resource for the game round
random_resource_id = random_resource.get(random_resource.id)
gameround = Gameround.objects.all().filter(taggings__resource_id=random_resource_id).order_by("?").first()

Это приводит к ошибке 'Response' object has no attribute 'id' when I reload the page in the browser.

Кто-нибудь знает, как я могу решить эту проблему?

Заранее спасибо!

Наконец, мне удалось решить эту проблему, переписав запрос get следующим образом:

def get(self, request, *args, **kwargs):

    random_resource = Resource.objects.all().order_by('?').first()
    resource_serializer = ResourceSerializer(random_resource)  # Response is a serialized JSON object
    random_resource_id = random_resource.id   # id of the random Resource for the game round
    gameround = Gameround.objects.all().filter(taggings__resource_id=random_resource_id).order_by("?").first()
    gameround_serializer = GameroundSerializer(gameround)

    return Response({
        'resource to coordinate': resource_serializer.data,
        'gameround': gameround_serializer.data,
    })
Вернуться на верх