Je dois insérer plus de 8000 enregistrements dans une base de données SQLite à l'aide de l'ORM de Django. Cette opération doit être exécutée en tant que cronjob environ une fois par minute.
Pour le moment, j'utilise une boucle for pour parcourir tous les éléments, puis les insérer un par un.
Exemple:
for item in items:
entry = Entry(a1=item.a1, a2=item.a2)
entry.save()
Quelle est la manière efficace de procéder?
Edit: Une petite comparaison entre les deux méthodes d'insertion.
Sans décorateur commit_manually (11245 enregistrements):
nox@noxdevel marinetraffic]$ time python manage.py insrec
real 1m50.288s
user 0m6.710s
sys 0m23.445s
Utilisation du décorateur commit_manually (11245 enregistrements):
[nox@noxdevel marinetraffic]$ time python manage.py insrec
real 0m18.464s
user 0m5.433s
sys 0m10.163s
Remarque: Le script de test effectue également d'autres opérations en plus de l'insertion dans la base de données (télécharge un fichier Zip, extrait un fichier XML à partir de l'archive Zip, analyse le fichier XML) de sorte que le temps nécessaire à l'exécution ne représente pas nécessairement le temps nécessaire pour insérer les enregistrements.
Vous voulez vérifier Django.db.transaction.commit_manually
.
http://docs.djangoproject.com/en/dev/topics/db/transactions/#Django-db-transaction-commit-manually
Ce serait donc quelque chose comme:
from Django.db import transaction
@transaction.commit_manually
def viewfunc(request):
...
for item in items:
entry = Entry(a1=item.a1, a2=item.a2)
entry.save()
transaction.commit()
Qui ne sera validé qu'une seule fois, à la place à chaque sauvegarde ().
Dans Django 1.3 gestionnaires de contexte ont été introduits. Alors maintenant, vous pouvez utiliser transaction.commit_on_success () d'une manière similaire:
from Django.db import transaction
def viewfunc(request):
...
with transaction.commit_on_success():
for item in items:
entry = Entry(a1=item.a1, a2=item.a2)
entry.save()
Dans Django 1.4, bulk_create
a été ajouté, vous permettant de créer des listes de vos objets de modèle, puis de les valider tous en même temps.
[~ # ~] note [~ # ~] la méthode de sauvegarde ne sera pas appelée lors de l'utilisation de la création en bloc.
>>> Entry.objects.bulk_create([
... Entry(headline="Django 1.0 Released"),
... Entry(headline="Django 1.1 Announced"),
... Entry(headline="Breaking: Django is awesome")
... ])
Dans Django 1.6, transaction.atomic a été introduit, destiné à remplacer maintenant les fonctions héritées commit_on_success
et commit_manually
.
à partir du Django documentation sur atomic :
atomic est utilisable aussi bien comme décorateur:
from Django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
et en tant que gestionnaire de contexte:
from Django.db import transaction
def viewfunc(request):
# This code executes in autocommit mode (Django's default).
do_stuff()
with transaction.atomic():
# This code executes inside a transaction.
do_more_stuff()
La création en masse est disponible dans Django 1.4:
https://Django.readthedocs.io/en/1.4/ref/models/querysets.html#bulk-create
Jetez un œil à this . Il est destiné à être utilisé prêt à l'emploi avec MySQL uniquement, mais il existe des pointeurs sur ce qu'il faut faire pour les autres bases de données.
Il est préférable de charger les éléments en bloc - préparez un fichier et utilisez un outil de chargement en bloc. Ce sera beaucoup plus efficace que 8000 inserts individuels.
Vous devriez vérifier DSE . J'ai écrit DSE pour résoudre ce genre de problèmes (insertion massive ou mises à jour). En utilisant le Django orm est une impasse, vous devez le faire en SQL simple et DSE s'occupe de beaucoup de cela pour vous.
Thomas
Pour répondre à la question en particulier concernant SQLite, comme demandé, alors que je viens de confirmer que bulk_create fournit une accélération considérable, il existe une limitation avec SQLite: "La valeur par défaut est de créer tous les objets en un seul lot, sauf pour SQLite où le la valeur par défaut est telle qu'au maximum 999 variables par requête sont utilisées. "
Les informations citées proviennent des documents --- A-IV a fourni un lien.
Ce que je dois ajouter, c'est que ce djangosnippets entrée par alpar semble également fonctionner pour moi. C'est un petit wrapper qui divise le gros lot que vous souhaitez traiter en lots plus petits, en gérant la limite de 999 variables.
def order(request):
if request.method=="GET":
# get the value from html page
cust_name = request.GET.get('cust_name', '')
cust_cont = request.GET.get('cust_cont', '')
pincode = request.GET.get('pincode', '')
city_name = request.GET.get('city_name', '')
state = request.GET.get('state', '')
contry = request.GET.get('contry', '')
gender = request.GET.get('gender', '')
paid_amt = request.GET.get('paid_amt', '')
due_amt = request.GET.get('due_amt', '')
order_date = request.GET.get('order_date', '')
prod_name = request.GET.getlist('prod_name[]', '')
prod_qty = request.GET.getlist('prod_qty[]', '')
prod_price = request.GET.getlist('prod_price[]', '')
# insert customer information into customer table
try:
# Insert Data into customer table
cust_tab = Customer(customer_name=cust_name, customer_contact=cust_cont, gender=gender, city_name=city_name, pincode=pincode, state_name=state, contry_name=contry)
cust_tab.save()
# Retrive Id from customer table
custo_id = Customer.objects.values_list('customer_id').last() #It is return Tuple as result from Queryset
custo_id = int(custo_id[0]) #It is convert the Tuple in INT
# Insert Data into Order table
order_tab = Orders(order_date=order_date, paid_amt=paid_amt, due_amt=due_amt, customer_id=custo_id)
order_tab.save()
# Insert Data into Products table
# insert multiple data at a one time from djanog using while loop
i=0
while(i<len(prod_name)):
p_n = prod_name[i]
p_q = prod_qty[i]
p_p = prod_price[i]
# this is checking the variable, if variable is null so fill the varable value in database
if p_n != "" and p_q != "" and p_p != "":
prod_tab = Products(product_name=p_n, product_qty=p_q, product_price=p_p, customer_id=custo_id)
prod_tab.save()
i=i+1
return HttpResponse('Your Record Has been Saved')
except Exception as e:
return HttpResponse(e)
return render(request, 'invoice_system/order.html')