Django插入多条数据 您所在的位置:网站首页 list如何存放一万条数据 Django插入多条数据

Django插入多条数据

2024-05-23 06:23| 来源: 网络整理| 查看: 265

在Django中需要向数据库中插入多条数据(list)。使用如下方法,每次save()的时候都会访问一次数据库。导致性能问题:

for i in resultlist: p = Account(name=i) p.save()

在django1.4以后加入了新的特性。使用django.db.models.query.QuerySet.bulk_create()批量创建对象,减少SQL查询次数。改进如下:

querysetlist=[] for i in resultlist: querysetlist.append(Account(name=i)) Account.objects.bulk_create(querysetlist) Model.objects.bulk_create() 更快更方便

常规用法:

#coding:utf-8 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") ''' Django 版本大于等于1.7的时候,需要加上下面两句 import django django.setup() 否则会抛出错误 django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet. ''' import django if django.VERSION >= (1, 7):#自动判断版本 django.setup() def main(): from blog.models import Blog f = open('oldblog.txt') for line in f: title,content = line.split('****') Blog.objects.create(title=title,content=content) f.close() if __name__ == "__main__": main() print('Done!')

使用批量导入:

import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") def main(): from blog.models import Blog f = open('oldblog.txt') BlogList = [] for line in f: title,content = line.split('****') blog = Blog(title=title,content=content) BlogList.append(blog) f.close() Blog.objects.bulk_create(BlogList) if __name__ == "__main__": main() print('Done!')

由于Blog.objects.create()每保存一条就执行一次SQL,而bulk_create()是执行一条SQL存入多条数据,做会快很多!当然用列表解析代替 for 循环会更快!!

#!/usr/bin/env python import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") def main(): from blog.models import Blog f = open('oldblog.txt') BlogList = [] for line in f: parts = line.split('****') BlogList.append(Blog(title=parts[0], content=parts[1])) f.close() # 以上四行 也可以用 列表解析 写成下面这样 # BlogList = [Blog(title=line.split('****')[0], content=line.split('****')[1]) for line in f] Blog.objects.bulk_create(BlogList) if __name__ == "__main__": main() print('Done!')

例如:

# 获取数量 nums = request.POST.get('nums').strip() if nums.isdigit() and int(nums) > 0: # 方法一 # for i in range(int(nums)): # device = Device( # category=category, # seat=seat_obj, # asset_code='', # asset_num='V{}-{}'.format(category.name, str(i).zfill(4)), # V类型-0001编号 # use_info='', # operator=operator, # op_type=1 # ) # device.save() # 每次save()的时候都会访问一次数据库。导致性能问题 # 方法二 device_obj_list = [] for i in range(int(nums)): device_obj_list.append( Device( category=category, seat=seat_obj, asset_code='---', asset_num='{}-xxxx'.format(category.name), # 类型-xxxx use_info='---', operator=operator, op_type=1 ) ) Device.objects.bulk_create(device_obj_list) # 使用django.db.models.query.QuerySet.bulk_create()批量创建对象,减少SQL查询次数 messages.info(request, '批量添加{}条数据完成!'.format(nums)) 批量导入时数据重复的解决方法

如果你导入数据过多,导入时出错了,或者你手动停止了,导入了一部分,还有一部分没有导入。或者你再次运行上面的命令,你会发现数据重复了,怎么办呢?

django.db.models 中还有一个函数叫 get_or_create(),之前文章中也提到过,有就获取过来,没有就创建,用它可以避免重复,但是速度可以会慢些,因为要先尝试获取,看看有没有

只要把上面的:

Blog.objects.create(title=title,content=content)

换成下面的就不会重复导入数据了

Blog.objects.get_or_create(title=title,content=content)

返回值是(BlogObject, True/False)新建时返回 True, 已经存在时返回 False。

事务探究

bulk_create来批量插入,可是使用了这个方法还需要在自己添加一个事务吗? 还是django本身对这个方法进行了事务的封装?

查看了源码(django1.5):在 django/db/models/query.py 中,看到这样的片段

with transaction.commit_on_success_unless_managed(using=self.db): if (connection.features.can_combine_inserts_with_and_without_auto_increment_pk and self.model._meta.has_auto_field): self._batched_insert(objs, fields, batch_size) else: objs_with_pk, objs_without_pk = partition(lambda o: o.pk is None, objs) if objs_with_pk: self._batched_insert(objs_with_pk, fields, batch_size) if objs_without_pk: fields= [f for f in fields if not isinstance(f, AutoField)] self._batched_insert(objs_without_pk, fields, batch_size)

这里我们看到了一个transaction的调用 transaction.commit_on_success_unless_managed(using=self.db),那么这句话是什么意思呢?

看看他的定义: django/db/transaction.py中

def commit_on_success_unless_managed(using=None, savepoint=False): """ Transitory API to preserve backwards-compatibility while refactoring. Once the legacy transaction management is fully deprecated, this should simply be replaced by atomic. Until then, it's necessary to guarantee that a commit occurs on exit, which atomic doesn't do when it's nested. Unlike atomic, savepoint defaults to False because that's closer to the legacy behavior. """ connection = get_connection(using) if connection.get_autocommit() or connection.in_atomic_block: return atomic(using, savepoint) else: def entering(using): pass def exiting(exc_type, using): set_dirty(using=using) return _transaction_func(entering, exiting, using)

没怎么看懂这个方法的解释,从代码结构来看应该是有事务的。

那自己做个试验把,往数据库批量插入2条数据,一个正确的,一个错误的看看结果如何?

ipython做了个试验

from mngm.models import Area a1=Area(areaname="China", code="CN", parentid='1', level='3') a2=Area(id=1, areaname="China", code="CN", parentid='1', level='3') #错误的记录 Area.objects.bulk_create([a1, a2]) IntegrityError: (1062, "Duplicate entry '1' for key 'PRIMARY'") a2=Area(areaname="Chinaa", code="CN", parentid='1', level='3') #正确的记录 Area.objects.bulk_create([a1, a2]) [, ]

所以这个操作框架已经实现了事务处理,不需要自己再添加事务就好了。

你可能正好不需要这种事务处理,看看



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有