如何避免在 Django 循环中多次访问数据库?

How to avoid making multiple trips to database in Django loop?

目前这段代码似乎在每次循环迭代中都要进入数据库 (Postgres) 两到四次。首先获取(并创建)Type,然后获取(并创建)Component。有没有一种方法可以减少数据库访问次数?

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