当每个 post 使用 UUID 而不是顺序 ID 时,如何在 Django 中有效地对随机 post 进行采样?
How can I efficiently sample random posts in Django, when each post uses UUIDs rather than sequential IDs?
我有一些 post 模型,其中 ID 是 UUID。
现在我想显示一些随机的 post 用户可能也喜欢在我的 post_detail 模板中看到的建议...
这就是我处理 post 提案的方式,用户可能还希望在 views.py:
上看到
def post_proposals():
post_elements = sorted(
chain(
Model1.objects.all(),
Model2.objects.all(),
Model3.objects.all()
)
)
post_elements_list = list(post_elements) # Conversion to list is requierd by random
post_proposals = random.sample(post_elements_list)
return post_proposals
def post_detail(request, pk):
...
args = {
'post': post,
'post_proposals': post_proposals(),
...
template.html:
{% for post_proposal in post_proposals %}
<h1>{{ post_proposal.title }}</h1>
{% endfor %}
现在的问题是,根据我的理解,这会降低我的数据库性能...一旦我的数据库中存储了很多 post,查询就会变得庞大。我首先必须获取 3 个模型的所有元素,然后每次向用户显示 post 时从列表中随机获取 10 个条目。
我还发现了以下似乎很有用的东西:
https://elpenia.wordpress.com/2010/05/11/getting-random-objects-from-a-queryset-in-django/
遗憾的是,我无法使用该解决方案,因为我使用的 UUID 是非顺序字符串,而不是 ID 所具有的 int 值。
问题是你有不同的模型,这使得操作非常昂贵。
我建议您添加一个新模型,其中您要查询的所有模型都注册为外键或 id/type 对。这样你就可以绕过设计缺陷,并且
仅拉取 ID:
model.objects.all().values_list('id',flat=True)。
random.sample 的结果将是 id,您可以直接使用 id 提取帖子
在新的 table 的 1 和 count() 之间生成一个随机范围,然后通过处理具有相应索引的记录来提取实际帖子。这将要求您添加一个索引字段,因为 id 可能不是连续的(删除和填充)
获得 ID 后,您可以使用 model.objects.filter(id__in=post_proposals) 提取集合并进一步处理
--- 编辑示例实现 ---
环绕其他模型的模型看起来像这样:
class Model1(models.Model):
@staticmethod
def get_ref_type(): return 0
def create(self):
super(Model1,self).create()
Posts.register(self,Model1.get_ref_type())
def delete(self):
Posts.un_register(self,Model1.get_ref_type())
super(Model1,self).delete()
class Posts(models.Model):
class Meta:
....
#sequential index, this is what you will filter against
index = models.IntegerField(default=0)
#type of the model you want to query
ref_type = models.IntegerField(default =-1)
#id of the record in the table defined in the ref_type field
ref_id = models.IntegerField(default =-1)
@staticmethod
def register(f_objRecord,f_intType):
l_objWrp = Posts()
#a separate table that will be used to hold the free indexes
#it will ensure that even when you delete records, there
#won't be any holes in the set
l_objWrp.index = PostIndex.get_index()
l_objWrp.ref_id = f_objRecord.id
l_objWrp.ref_type = f_intType
l_objWrp.save()
@staticmethod
def un_register(f_objRecord,f_intType):
l_objWrp = Posts.objects.get(ref_type=f_intType,ref_id=f_objRecord.id)
PostIndex.free_index(l_objWrp.index)
l_objWrp.delete()
def get_data(self):
l_intRefType = self.ref_type
l_intId = self.ref_id
l_objRecord = None
if l_intRefType == Model1.get_ref_type():
l_objRecord = Model1.objects.get(id=l_intId)
elif l_intRefType == Model2.get_ref_type():
.....
if l_objRecord:
#pull the data you want
else: raise('unknown model type')
你可以尝试让数据库随机排序然后切片,例如
Model1.objects.order_by('?')[:3]`.
order_by
文档警告说这可能代价高昂且速度缓慢,但可能值得进行测试,看看它在实践中是否能提供可接受的结果。
我有一些 post 模型,其中 ID 是 UUID。 现在我想显示一些随机的 post 用户可能也喜欢在我的 post_detail 模板中看到的建议...
这就是我处理 post 提案的方式,用户可能还希望在 views.py:
上看到def post_proposals():
post_elements = sorted(
chain(
Model1.objects.all(),
Model2.objects.all(),
Model3.objects.all()
)
)
post_elements_list = list(post_elements) # Conversion to list is requierd by random
post_proposals = random.sample(post_elements_list)
return post_proposals
def post_detail(request, pk):
...
args = {
'post': post,
'post_proposals': post_proposals(),
...
template.html:
{% for post_proposal in post_proposals %}
<h1>{{ post_proposal.title }}</h1>
{% endfor %}
现在的问题是,根据我的理解,这会降低我的数据库性能...一旦我的数据库中存储了很多 post,查询就会变得庞大。我首先必须获取 3 个模型的所有元素,然后每次向用户显示 post 时从列表中随机获取 10 个条目。
我还发现了以下似乎很有用的东西:
https://elpenia.wordpress.com/2010/05/11/getting-random-objects-from-a-queryset-in-django/
遗憾的是,我无法使用该解决方案,因为我使用的 UUID 是非顺序字符串,而不是 ID 所具有的 int 值。
问题是你有不同的模型,这使得操作非常昂贵。 我建议您添加一个新模型,其中您要查询的所有模型都注册为外键或 id/type 对。这样你就可以绕过设计缺陷,并且
仅拉取 ID: model.objects.all().values_list('id',flat=True)。 random.sample 的结果将是 id,您可以直接使用 id 提取帖子
在新的 table 的 1 和 count() 之间生成一个随机范围,然后通过处理具有相应索引的记录来提取实际帖子。这将要求您添加一个索引字段,因为 id 可能不是连续的(删除和填充)
获得 ID 后,您可以使用 model.objects.filter(id__in=post_proposals) 提取集合并进一步处理
--- 编辑示例实现 ---
环绕其他模型的模型看起来像这样:
class Model1(models.Model):
@staticmethod
def get_ref_type(): return 0
def create(self):
super(Model1,self).create()
Posts.register(self,Model1.get_ref_type())
def delete(self):
Posts.un_register(self,Model1.get_ref_type())
super(Model1,self).delete()
class Posts(models.Model):
class Meta:
....
#sequential index, this is what you will filter against
index = models.IntegerField(default=0)
#type of the model you want to query
ref_type = models.IntegerField(default =-1)
#id of the record in the table defined in the ref_type field
ref_id = models.IntegerField(default =-1)
@staticmethod
def register(f_objRecord,f_intType):
l_objWrp = Posts()
#a separate table that will be used to hold the free indexes
#it will ensure that even when you delete records, there
#won't be any holes in the set
l_objWrp.index = PostIndex.get_index()
l_objWrp.ref_id = f_objRecord.id
l_objWrp.ref_type = f_intType
l_objWrp.save()
@staticmethod
def un_register(f_objRecord,f_intType):
l_objWrp = Posts.objects.get(ref_type=f_intType,ref_id=f_objRecord.id)
PostIndex.free_index(l_objWrp.index)
l_objWrp.delete()
def get_data(self):
l_intRefType = self.ref_type
l_intId = self.ref_id
l_objRecord = None
if l_intRefType == Model1.get_ref_type():
l_objRecord = Model1.objects.get(id=l_intId)
elif l_intRefType == Model2.get_ref_type():
.....
if l_objRecord:
#pull the data you want
else: raise('unknown model type')
你可以尝试让数据库随机排序然后切片,例如
Model1.objects.order_by('?')[:3]`.
order_by
文档警告说这可能代价高昂且速度缓慢,但可能值得进行测试,看看它在实践中是否能提供可接受的结果。