2017-01-18 5 views
1

Ich arbeite an einem Django-Projekt (Django 1.10, Python 3.4.3), wo ich versuche, eine Datei in einen Python-Subprozess hochzuladen. Ich muss die Datei hochladen und einige Summen berechnen, während ich sie hochlade, und wir möchten, dass das System währenddessen noch verwendbar ist. Daher dachten wir, diese Aufgaben in einen Subprozess zu stellen.Hochladen einer Datei in einen Python-Subprozess

Momentan arbeite ich gerade daran, die Datei hochzuladen.

Erster Versuch:

app/views/UploadView.py

class NewUploadView(TemplateView): 
    template_name = "../templates/simulation/upload.html" 

    @transaction.atomic 
    def post(self, request): 
     if request.method == 'POST': 
      if not request.FILES['input_file']: 
       return HttpResponseBadRequest("No 'input_file' is provided") 
      else: 
       sim_name = self.request.POST.get(u"name", None) 

       p = Popen(["/.virtualenvs/env/bin/python3.4", "manage.py", 
        "load_simulation", str(request.FILES['input_file'], 
        str(sim_name)]) 

       p.communicate() 

       # Redirect to appropriate page 
       HttpResponseRedirect(reverse('home.display_simulations'))` 

app/Management/Befehle/load_simulation.py

import csv 
import os 

from django.conf import settings 
from django.core.management.base import BaseCommand 

from website.apps.home.models import Simulation, Location, Data, SimulationModel 


class Command(BaseCommand): 
    help = 'Upload csv data file and save objects in database' 

    def add_arguments(self, parser): 
     parser.add_argument("my_file", type=str) 
     parser.add_argument("simulation_name", type=str) 

    def handle(self, *args, **options): 
     """ 
     Upload data file 
     :param args: 
     :param options: 
     :return: 
     """ 
     my_file = options["my_file"] 
     simulation_name = options["simulation_name"] 

     # Save the simulation object, with the data_file 
     simulation = Simulation.objects.create(name=simulation_name, data_file=my_file) 
     simulation.save() 

     filename = os.path.join(settings.MEDIA_ROOT, "simulation_files", simulation.getfilename()) 
     file_obj = open(filename, 'r') 
     dictreader = csv.DictReader(file_obj) 
     line = None 

     for line in dictreader: 
      location = Location.objects.filter(
       department_code=line['department_code'], 
       municipality_code=line['municipality_code'], 
      ).first() 

      if not location: 
       location = Location.objects.create(
        department=line['department'], 
        department_code=line['department_code'], 
        municipality=line['municipality'], 
        municipality_code=line['municipality_code'], 
       ) 

      Data.objects.create(
       location=location, 
       date=line['date'].split(" ")[0], # Assuming date is in "YYYY-MM-DD HH:MM:SS" format 
       simulation=simulation, 
       value_low=line['value_low'], 
       value_mid=line['value_mid'], 
       value_high=line['value_high'], 
      ) 

     simulation.is_uploaded = True 
     simulation.save() 
     print("DONE WITH LOAD SIMULATION!") 

ich es habe eingerichtet, so dass die Datei ingespeichert wirdVerzeichnis. Die Datei wird jedoch nicht auf dem Server gespeichert, was bedeutet, dass sie in der Datei load_simulation.py an der Zeile fehlschlägt, in der sie versucht, die Datei zu öffnen, da sich die Datei nicht an diesem Speicherort befindet.

Dann erkannte ich, dass ich eine temporäre Datei als Zeichenfolge übergeben, also ist das vielleicht ein Teil des Problems.

zweiter Versuch

Ich änderte Teil UploadView.py in der Datei als stdin zu nehmen.

 p = Popen(["/.virtualenvs/env/bin/python3.4", "manage.py", 
           "load_simulation", str(sim_name), is_historical], 
           stdin=PIPE) 

     p.communicate(input=request.FILES['output_file']) 

und modifizierte load_simulation.py beginnen wie folgt:

class Command(BaseCommand): 
    help = 'Upload csv data file and save objects in database' 

    def add_arguments(self, parser): 
     parser.add_argument("my_file", type=str) 
     parser.add_argument("simulation_name", type=str) 

    def handle(self, *args, **options): 
     """ 
     Upload data file 
     :param args: 
     :param options: 
     :return: 
     """ 

     simulation_name = options["simulation_name"] 

     my_file = input() 

     # Save the simulation object, with the data_file 
     simulation = Simulation.objects.create(name=simulation_name, data_file=my_file.name) 
     simulation.save() 

     filename = os.path.join(settings.MEDIA_ROOT, "simulation_files", simulation.getfilename()) 
     file_obj = open(filename, 'r') 
     dictreader = csv.DictReader(file_obj) 

     ... same as before ...  

, die ich aus der folgenden Frage/Antwort bekam: Python3 subprocess communicate example

Das gibt mir einen Fehler

TypeError: 'InMemoryUploadedFile' does not support the buffer interface

Ich bin neu mit Subprozessen zu arbeiten und bin ratlos, was ich als nächstes versuchen soll. Ich bin mir bewusst, dass p.communicate() hier vielleicht nicht die beste Wahl ist, aber ich hoffe, dass es funktionieren wird, um die grundlegende Funktionalität herunter zu bekommen und dann kann ich sie verbessern. Vorschläge und Ratschläge werden sehr geschätzt!

Antwort

0

Alles klar, ich habe mein grundlegendes Problem gelöst, eine Datei in einem Unterprozess hochzuladen. Die Datei wird unter /media/simulation_files gespeichert, wenn das Objekt Simulation erstellt wird. Aus irgendeinem Grund funktioniert dies nicht, wenn der Simulation im Unterprozess gespeichert wird, also habe ich das in die Ansicht verschoben und das Objekt gespeichert, bevor ich den Unterprozess erstelle.

Dann benötigt die Popen nur die ID des neu erstellten Simulation als Argument, um auf die gesamte Simulation (einschließlich der Datendatei) zugreifen zu können.

Wichtige:

ich sonst die @transaction.atomic Dekorateur entfernen musste, das Simulation Objekt in der Ansicht erstellt wird im Subprozess nicht zugänglich sein.

tl; dr Version:

UploadView.py

class NewerUploadView(TemplateView): 
    template_name = "../templates/simulation/upload.html" 

    def post(self, request): 
     if request.method == 'POST': 
      if not request.FILES['output_file']: 
       return HttpResponseBadRequest("No 'output_file' is provided") 
      else: 
       sim_name = self.request.POST.get(u"name", None) 

       # Create the Simulation here to save the file 
       simulation = Simulation.objects.create(name=simulation_name, 
                 data_file=fp) 
       simulation.save() 

       # Get the new Simulation object 
       new_sim = Simulation.objects.get(id=sim_id) 

       p = Popen(["/.virtualenvs/env/bin/python3.4", "manage.py", 
        "load_simulation", str(new_sim.id)], stdout=PIPE, stderr=PIPE) 
       p.communicate() 

       # Redirect to appropriate page 
       return HttpResponseRedirect(reverse('home.display_simulations')) 

load_simulation.py

class Command(BaseCommand): 
    help = 'Upload csv data file and save objects in database' 

    def add_arguments(self, parser): 
     parser.add_argument("sim_id", type=int) 

    def handle(self, *args, **options): 
     """ 
     Upload data file 
     :param args: 
     :param options: 
     :return: 
     """ 

     sim_id = options["sim_id"] 
     sim = Simulation.objects.get(id=sim_id) 
     filename = os.path.join(settings.MEDIA_ROOT, sim.data_file.name) 
     file_obj = open(filename, 'r') 
     dictreader = csv.DictReader(file_obj) 
     line = None 

     for line in dictreader: 

      location = Location.objects.filter(
       department_code=line['department_code'], 
       municipality_code=line['municipality_code'], 
      ).first() 

      if not location: 
       location = Location.objects.create(
        department=line['department'], 
        department_code=line['department_code'], 
        municipality=line['municipality'], 
        municipality_code=line['municipality_code'], 
       ) 

      Data.objects.create(
       location=location, 
       date=line['date'].split(" ")[0], # Assuming "YYYY-MM-DD HH:MM:SS" 
       simulation=sim, 
       value_low=line['value_low'], 
       value_mid=line['value_mid'], 
       value_high=line['value_high'], 
      ) 
     sim.is_uploaded = True 
     sim.save() 
     print("DONE WITH LOAD SIMULATION!")