如何协调 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,
})
我正在为游戏构建 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,
})