如何避免在Django循环中多次访问数据库?
问题描述:
目前,这个代码似乎要在每次循环迭代时发送到数据库(Postgres)两到四次。首先获取(并创建)Type
,然后获取(并创建)Component
。有没有办法在更少的数据库旅程中做到这一点?如何避免在Django循环中多次访问数据库?
models.py
:
class Component(models.Model):
long = models.TextField()
type = models.SmallForeignKey('Type', models.CASCADE)
class Type(models.Model):
type = models.TextField(unique=True)
class Point(models.Model):
components = models.ArrayField(models.IntegerField(), default=[])
def save_components(self, geocode):
_components = []
for c in geocode:
ct = Type.objects.get_or_create(type=c['types'][0])
_components.append(Component.objects.get_or_create(long=c['long_name'], type=ct).pk)
self.components = _components
self.save()
传入数据:
geocode = [
{
"long_name" : "Luray",
"types" : [ "locality", "political" ]
},
{
"long_name" : "Page County",
"types" : [ "administrative_area_level_2", "political" ]
},
{
"long_name" : "Virginia",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "United States",
"types" : [ "country", "political" ]
}
]
答
很多的时候,Django的做一个体面的工作缓存数据库结果。如果你想有更多的控制,你可以做这样的事情(前提是你没有太多的类型)
class Point(models.Model): components = models.ArrayField(models.IntegerField(), default=[]) def save_components(self, geocode): _components = [] _types = {t.type: t for t in Type.objects.all()} for c in geocode: ct = _types.get(c['types'][0], None) if not ct: ct = Type.objects.create(type=c['types'][0]) _components.append(Component.objects.get_or_create(long=c['long_name'], type=ct).pk) self.components = _components self.save()
这应该救你查找现有类型所有的时间。您也可以尝试推迟创建新类型和新组件(使用get()而不是get_or_create()并捕获DoesNotExist异常)并稍后在函数中使用批量插入(这里是doc link)
OK,'ct'和'组件'不是从哪里冒出来的,它们都是从数据库中提取出来的,你怎么不能触及数据库并获取信息呢? –
@ShangWang我想应该可以在本地缓存,但这不是问题。目标是减少旅行次数,可能会减少到1或2次。我怀疑这是可能的,因为在第一次旅行时所有的信息已经存在。 – dtgq
为什么你要存储一个主键数组,而不是使用ManyToManyField? –