【问题标题】:How to avoid making multiple trips to database in Django loop?如何避免在 Django 循环中多次访问数据库?
【发布时间】:2017-05-24 00:48:31
【问题描述】:

目前,此代码似乎在每次循环迭代中都会进入数据库 (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" ]
    }
]

【问题讨论】:

  • 好吧,ctcomponent不是凭空冒出来的,都是从数据库中取来的,怎么不打数据库就可以得到信息呢?
  • @ShangWang 好吧,我想可以在本地缓存它,但这不是问题。目标是减少旅行次数,可能减少到 1 次或 2 次。我怀疑这是可能的,因为在第一次旅行时所有信息都已经存在。
  • 为什么要存储主键数组,而不是使用 ManyToManyField?
  • 首先,您必须查询TypeComponent 是否存在,每个都需要一个sql 查询,这是毫无疑问的。如果它们不存在,则必须创建它们,另外 1 或 2 个创建 sql 语句将被发送到数据库。我不确定你是什么意思all information is already there,如果没有存储,你不想创建它们吗?也正如@DanielRoseman 所说:docs.djangoproject.com/en/1.10/topics/db/examples/many_to_many
  • @DanielRoseman 我一直在犹豫是否应该使用数组或直通表...如果我想切换回来,我已经编写了使用 M2M 的代码(即甚至更臃肿),但数组对于我想要使用的查询更有意义。我们现在可以回到主题了吗?

标签: django django-queryset django-orm


【解决方案1】:

很多时候,Django 在缓存数据库结果方面做得不错。如果你想拥有更多的控制权,你可以这样做(前提是你没有太多的类型)

类点(模型。模型): 组件 = models.ArrayField(models.IntegerField(), default=[]) def save_components(自我,地理编码): _components = [] _types = {t.type: t for t in Type.objects.all()} 对于地理编码中的 c: ct = _types.get(c['types'][0], 无) 如果不是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 自我保存()

这应该可以让您一直查找现有类型。您还可以尝试推迟创建新类型和新组件(使用 get() 而不是 get_or_create() 并捕获 DoesNotExist 异常)并稍后在函数中使用批量插入(这里是 doc link

【讨论】:

    猜你喜欢
    • 2020-06-14
    • 1970-01-01
    • 2017-09-05
    • 2020-10-09
    • 2015-05-31
    • 1970-01-01
    • 2017-07-10
    • 2021-05-28
    • 2021-02-12
    相关资源
    最近更新 更多