如何协调 DRF APIView 中随机选择的对象?

How to coordinate randomly chosen objects in a DRF APIView?

我正在为游戏构建 API,需要 select 随机选择资源的随机游戏回合。

选择随机资源有效。我现在想做的是,为了协调玩家,根据随机选择的资源过滤游戏回合,然后 return 随机游戏回合。

下面的代码显示了我到目前为止所做的尝试,即通过使用 @属性 装饰器的方法访问已经玩过一局游戏的资源。

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

在视图中,我有一个获取请求,它首先选择一个随机资源,然后我试图过滤游戏回合以仅包括涉及该资源的那些,然后我试图检索一个随机游戏回合.

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)

这似乎不起作用,因为我不断收到错误消息“响应内容必须在迭代之前呈现。”

我也试过创建一个 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' 错误。

有谁知道我该如何解决这个问题?

提前致谢!

下方还有Gameviewcontroller,它位于views.py文件

class GameViewController:

        def get_random_object(self, MyModel):
        random_object = None
        object_count = MyModel.objects.all().count() + 1
        while not MyModel.objects.all().filter(id=random_object).exists():
            for obj in range(object_count):
                n = random.randint(1, object_count)
                if MyModel.objects.all().filter(id=n).exists():
                    random_object = n
                    return random_object

def get_random_id(self, MyModel):
        """Method for large querysets"""
        random_object = None
        object_count = MyModel.objects.all().count() + 1
        for obj in range(object_count):
            n = random.randint(1, object_count)
            while not MyModel.objects.all().filter(id=n).exists():
                alt = random.randint(1, object_count)
                if MyModel.objects.all().filter(id=alt).exists():
                    random_object = n

        return random_object

    def get_resource(self):
        random_resource_id = self.get_random_object(Resource)
        current_resource = Resource.objects.all().filter(id=random_resource_id)
        resource_serializer = ResourceSerializer(current_resource, many=True)
        data = {'resource': resource_serializer.data}
        return Response(data, status=status.HTTP_200_OK)

    def get_gameround_matching_resource(self, random_resource):
        """Checks if a previously played game round exists for a randomly chosen resource"""
        current_gameround = Gameround.objects.all().filter(ressource__in=random_resource).order_by('?').first()

        if current_gameround.exists():
            gameround_serializer = GameroundSerializer(current_gameround)
            data = {'gameround': gameround_serializer.data}
            return Response(data, status=status.HTTP_200_OK)

    def timer(self, start):
        """Start a new timer as soon as a gameround has been selected"""
        start_time = start
        elapsed_time = None
        if start_time is not None:
            start_time = time.perf_counter()
        """Stop the timer, and return the elapsed time"""
        if start_time is None:
            elapsed_time = time.perf_counter() - start_time
        return elapsed_time

    def get_gamesession(self):
        """Retrieves a randomly chosen gamesession object"""
        current_gamesession = Gamesession.objects.all().order_by('?').first()
        gamesession_serializer = GamesessionSerializer(current_gamesession)
        data = {'gameround': gamesession_serializer.data}
        return Response(data, status=status.HTTP_200_OK)

我终于通过重写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,
    })