如何让Django中两个随机样本匹配相同外键Race值
问题描述
我正在开发一个生成随机奇幻角色名的Django应用,使用以下模型:
class VillagerFirstNames(models.Model): first_name=models.CharField(max_length=30, unique=True) race = models.ForeignKey(Race, on_delete=models.CASCADE) def __str__(self): return self.first_name class VillagerLastNames(models.Model): last_name = models.CharField(max_length=30, unique=True) race = models.ForeignKey(Race, on_delete=models.CASCADE) def __str__(self): return self.last_name
问题出在视图中:为了使用random.sample获取随机样本,我需要将查询集转为列表,代码如下:
foreign_first = list(VillagerFirstNames.objects.all()) foreign_first_random = random.sample(foreign_first, 3) context["foreign_first"] = foreign_first_random foreign_last = list(VillagerLastNames.objects.filter(race__race=foreign_first_random.race)) context["foreign_last"] = random.sample(foreign_last, 3)
我希望获取的姓氏与随机抽取的名字属于相同Race,但上述写法中,foreign_first_random是列表,不存在race属性,无法实现匹配,请求解决方法。
解决方案
根据需求场景,提供两种可行的实现方式:
场景1:生成的3组姓名统一属于同一个随机种族
先随机选定一个种族,再基于该种族抽取对应的名字和姓氏:
# 随机获取一个种族实例 random_race = Race.objects.order_by('?').first() # 抽取该种族下的3个名字(先判断数据量避免报错) first_name_candidates = list(VillagerFirstNames.objects.filter(race=random_race)) foreign_first_random = random.sample(first_name_candidates, 3) if len(first_name_candidates) >=3 else first_name_candidates context["foreign_first"] = foreign_first_random # 抽取同一种族下的3个姓氏 last_name_candidates = list(VillagerLastNames.objects.filter(race=random_race)) foreign_last = random.sample(last_name_candidates, 3) if len(last_name_candidates) >=3 else last_name_candidates context["foreign_last"] = foreign_last
场景2:每个名字匹配对应种族的姓氏(3个名字可来自不同种族)
遍历抽取到的名字列表,逐个获取对应种族的姓氏:
foreign_first = list(VillagerFirstNames.objects.all()) foreign_first_random = random.sample(foreign_first, 3) context["foreign_first"] = foreign_first_random # 为每个名字匹配同种族的姓氏 foreign_last_list = [] for name_obj in foreign_first_random: # 获取当前名字所属种族的姓氏集合 race_last_names = list(VillagerLastNames.objects.filter(race=name_obj.race)) if race_last_names: # 随机选一个姓氏添加到列表 foreign_last_list.append(random.choice(race_last_names)) context["foreign_last"] = foreign_last_list
补充说明
order_by('?')是Django中随机获取单条数据的常规写法,数据量不大时性能足够。- 抽取样本前判断列表长度,避免
random.sample因样本数量不足抛出异常。
内容的提问来源于stack exchange,提问作者Colin Crusott
相关产品推荐
相关产品推荐

