[PYTHON] [Django] Commande pour générer QuerySet en csv

J'ai écrit un code qui émet une sélection dans une table qui stocke un grand nombre d'enregistrements, envoie le résultat au csv et le gzip, alors prenez note.

models.py


from logging import getLogger
from django.db import models
import uuid

logger = getLogger(__name__)


class Analytics(models.Model):

    hit_type = models.CharField(max_length=20)

    category = models.CharField(max_length=255, null=True, blank=True)
    action = models.CharField(max_length=255, null=True)
    label = models.CharField(max_length=255, null=True, blank=True)
    value = models.IntegerField(null=True)
    url = models.CharField(max_length=255, null=True)
    created = models.DateTimeField(auto_now_add=True, db_index=True)
    tracking_user = models.ForeignKey('app.TrackingUser', related_name='analytics')

    def __str__(self):
        return '%s - %s' % (self.category, self.tracking_user.uuid)


class TrackingUser(models.Model):

    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return str(self.uuid)

Il y avait un modèle qui stockait les données qui suivaient le comportement des utilisateurs sur le site Web comme décrit ci-dessus, mais cette fois, je voulais créer une commande qui peut supprimer après avoir acquis des enregistrements Analytics pendant un mois et les stocker dans csv. .. Soit dit en passant, les données Analytics augmentent d'environ 100 000 en un jour, soit environ 3 millions en un mois. Donc, à la suite de diverses choses, le code suivant était un bon sentiment.

delete_analytics.py


from datetime import datetime, timedelta, date
from api.models import Analytics
from pytz import timezone, utc
from django.core.management.base import BaseCommand
from django.db import transaction
from dateutil.relativedelta import relativedelta
import csv
import gzip
import shutil
import os

class Command(BaseCommand):
    def add_arguments(self, parser):
        # Named (optional) arguments
        parser.add_argument('--target_date', metavar='target_date', type=str, nargs=None,
                            help='target date')

    @transaction.atomic
    def handle(self, *args, **options):
        if options['target_date']:
            delete_start_date = datetime.strptime(options['target_date'], '%Y-%m-%d').replace(day=1)
        else:
            this_month = date.today().replace(day=1)
            delete_start_date = this_month - relativedelta(months=3)
        delete_end_date = delete_start_date + relativedelta(months=1)

        queryset = Analytics.objects.select_related('user', 'tracking_user').filter(created__range=(delete_start_date, delete_end_date))

        #Sortie vers csv
        filename_date = delete_start_date.strftime('%Y%m')
        filename = filename_date + "_event.csv"

        model = queryset.model
        writer = csv.writer(open(filename, 'w'))

        ##Ecrire la partie en-tête de csv
        headers = []
        for field in model._meta.fields:
            headers.append(field.name)
        writer.writerow(headers)

        ##Ecrire l'enregistrement récupéré
        for obj in queryset:
            row = []
            for field in headers:
                val = getattr(obj, field)
                if callable(val):
                    val = val()
                row.append(val)
            writer.writerow(row)

        #Compresser csv avec gzip
        with open(filename, 'rb') as gzip_in:
            with gzip.open(filename + ".gz", 'wb') as gzip_out:
                shutil.copyfileobj(gzip_in, gzip_out)

        os.remove(filename)

        queryset.delete()

Si vous définissez ./manage.py delete_analytics.py -target_date = 2017-06-01 dans le répertoire où se trouve manage.py, les données de juin 2017 seront générées dans 201706_event.csv, ensuite compressées avec gzip, puis , Supprimé.
Les parties suivantes ont été la clé cette fois.

python


queryset = Analytics.objects.select_related( 'tracking_user').filter(created__range=(delete_start_date, delete_end_date))

Si vous n'écrivez pas select_related ('tracking_user')., La destination de la relation ira également à select, donc cela prendra du temps. Quand je l'ai écrit, la commande s'est terminée en 5 minutes, mais si je ne l'ai pas écrite, il a fallu 50 minutes pour terminer.

Postscript

Quand je l'ai exécuté sur le serveur, il est tombé en raison d'un manque de mémoire ... Réfléchissez à ce qu'il faut faire et réécrivez si vous pouvez le gérer

Lien de référence

django recipe: dump your queryset out as a csv file . palewire

Recommended Posts

[Django] Commande pour générer QuerySet en csv
Sortie vers un fichier csv avec Python
[Django] Convertir l'ensemble de requêtes en liste de types de dict
Python> Numéros de sortie de 1 à 100, 501 à 600> Pour csv
Afficher les informations utilisateur, etc. dans le journal Django
Commande Django + Docker
Convertir XLSX en CSV sur la ligne de commande
Sortie PDF avec Django
Sortie Markdown avec Django
impossible d'importer django
[Python-pptx] Afficher les informations de police PowerPoint au format csv avec python
Paramètres d'achèvement de la commande Django
mettre à jour django version 1.11.1 vers 2.2
J'ai fait une commande pour générer un commentaire pour une table dans Django
Exportez les informations produit au format CSV à l'aide de l'API de recherche de produits Rakuten [Python]
Introduction à Python Django (2) Win
Alternative à la commande dumpdata de django
Commande pour générer un code QR
Sortie de la structure de table dans Django
Shell pour créer un projet django
Écrire en csv avec Python
Convertissez rapidement SDF en CSV
Sortie de débogage de la commande calice
Passer du texte à Django genericview
Déployer le projet django sur heroku
[Mémo d'apprentissage] Résumé de la commande Django
[systemd] Commande pour supprimer le service
Introduction à la commande vi (Remarque)
Décorateur pour désactiver la sortie standard
Appuyez sur la commande echo dans le terminal Mac pour afficher Hello World
Comment afficher le résultat de sortie de la commande man Linux dans un fichier