web-dev-qa-db-fra.com

Quel est un moyen efficace d'insérer des milliers d'enregistrements dans une table SQLite à l'aide de Django?

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.

67
user11617

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()
118
monkut

La création en masse est disponible dans Django 1.4:

https://Django.readthedocs.io/en/1.4/ref/models/querysets.html#bulk-create

11
A-IV

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.

3
Vinay Sajip

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

2
Weholt

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.

2
Mike O'Connor
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')
0
Mohit Mishra