Django und erstellte Dateien downloaden

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Mittwoch 3. September 2008, 13:20

Hallo Leute,
ich hab mit Django ein Webinterface geschrieben was mir mehrere Textdateien schreibt. Jetzt suche ich nach einer brauchbaren Lösung wie ich die erstellten Dateien zur Verfügung stelle.

Das senden der Informationen aus dem Interface zu meinem Pythonscript geschieht über AJAX an einen View.

Mein Problem, das erstellen der Dateien kann schon mal mehrere Minuten dauern. Dh, meine view sollte irgendetwas zurückgeben, damit der AJAX Request nicht abgebrochen wird.
Meine Idee war einen Link zu einem Ordner zurück zu geben. In diesem Ordner will ich die Textdateien speichern, damit der User diese runterladen kann.

Kann mir jemand sagen welchen return ich in dem View machen muss? Wie kann ich das mit der Zeit lösen, also das ein User schon den Link bekommt, obwohl das ganze Script noch nicht fertig ist.
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 3. September 2008, 14:19

Der User bekommt keinen direkten Link zu einer Datei, sondern immer den selben Link zu einer Art "persönlichen Download Ordner" in dem alle schon fertig generierten Dateien aufgelistet werden.

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Mittwoch 3. September 2008, 14:22

Das ist genau sowas was ich mir vorstelle. Hast Du eine Idee wie ich sowas realisiere? Bzw ne Quelle?
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Freitag 12. September 2008, 09:54

jens hat geschrieben:Der User bekommt keinen direkten Link zu einer Datei, sondern immer den selben Link zu einer Art "persönlichen Download Ordner" in dem alle schon fertig generierten Dateien aufgelistet werden.
Hallo Jens,
ich würde gerne Deine Idee aufgreifen, mir fehlen im Moment ein paar Hinweise wie ich da vorgehen sollte.
Zum einen, was muss ich dem Browser für einen return geben, damit im Hintergrund mein pythoncode weiter arbeiten kann.

Zum anderen dieser quasi persönliche ordner, ich denke den muss ich doch irgendwie in meine urls.py eintrage damit ich da von außen drauf kann, oder?

Ich hab leider echt keine Idee wie ich da vorgehen soll und wäre für einen Hinweis dankbar...
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 12. September 2008, 10:28

würmchen hat geschrieben:Zum einen, was muss ich dem Browser für einen return geben, damit im Hintergrund mein pythoncode weiter arbeiten kann.
Einen Redirect zur generierten Datei. Oder, und das macht der MVV so, eine Seite mit "Datei anfordern" Link.
würmchen hat geschrieben:Zum anderen dieser quasi persönliche ordner, ich denke den muss ich doch irgendwie in meine urls.py eintrage damit ich da von außen drauf kann, oder?
Wieso? Ich würde das in die statischen Dateien tun, das ist ja Unsinn es von Django ausliefern zu lassen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 12. September 2008, 10:28

Der Persönliche Ordner ist ja quasi nichts anderes, als die Daten welche Datei welcher User laden darf.
Als erstes würde ich mal das Model dazu aufbauen. Dann ein view der die Daten des Models anzeigt und da abhängig davon welcher User gerade eingeloggt ist.
Die urls muß natürlich auf diesen view zeigt...

EDIT: Das Grundproblem bleibt aber: Die sicherheit das nur ein berechtigter Anwender die Dateien laden kann.
Man kann die Dateien nicht im http doc root legen. Somit sind diese nicht per Apache downloadbar. Dann muß die django app selber die Dateien ausliefern, was etwas mehr Preformance kosten.
Eine andere Variante wäre es evtl. eine .htaccess dynamisch zu generieren und die Passwörter von django darein zu stecken. Oder aber den Zugriff auf die IP Adresse zu limitieren (was aber wohl nicht ganz sicher ist)...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Montag 15. September 2008, 08:31

Einen Redirect zur generierten Datei. Oder, und das macht der MVV so, eine Seite mit "Datei anfordern" Link.
[/quote]
Genau so hab ich mir das auch vorgestellt. Mein Problem ist, das ich diese Abfrage mit AJAX sende und da auf eine Antwort gewartet wird. Ich mache das mit Jquery:

Code: Alles auswählen

	$("#get_all_pdb").livequery("click",function(){
		var pdb_keys = ""
		$("td.entry_key input[@type=checkbox][@checked]").each(function() {
			pdb_keys = pdb_keys+" "+$(this).attr("value");
		});
		$.ajax({
			type: "POST",
			timeout: 600000,
			data: "entry_key_string="+pdb_keys+"&database="+$("p input[@type=radio][@checked]").attr("value"),
			url: "createpdb/",
			beforeSend: function(){
				$("#loader").show();
			},
			success: function(data) {
				$('#result').after(data)
			},
			complete: function() {
				$("#loader").hide();
			}
		});
	});
Meine view sieht an der Stelle so aus:

Code: Alles auswählen

def createAllPdb(request):
    from bif.interface.interface import WebInterface
    from bif.interface.writer import CreatePdbFiles
    from bif.interface import output
    interface = WebInterface(request.POST['database'],
            request.session.get('tablename'))
    cursor = interface.getCursor()
    creator = CreatePdbFiles(cursor,'logfile.log')
    creator.createAllPdbFiles(request.POST['entry_key_string'])

    return render_to_response('interface/addinfo.html',
            {'result': 'nix',
                'string':''})
Jetzt fängt bei dem Funktionsaufruf createAllPdbFiles() mein Script an zu arbeiten und das brauch eben seine Zeit. WÄREND das arbeitet würde ich gerne auf eine Seite umleiten die mir diesen Link präsentiert auf dem der User dann nach XX Minuten die fertigen Dateien downloaden kann.
Ich hab aber keine Ahnung wie ich das vorzeitig "melde"...


Leonidas hat geschrieben:Wieso? Ich würde das in die statischen Dateien tun, das ist ja Unsinn es von Django ausliefern zu lassen.
Ich dachte mir jetzt auch das ich das mit richtigen Dateien mache und diese in einem Ordner der eben direkt zugänglich ist bereit stelle.

Wäre für einen Tip nochmal dankbar.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 15. September 2008, 09:36

Ich würde im View eine Art Token generieren, was an den User zurückgeschickt wird und gleichzeitig an den Dateigenerator in einem anderen Thread. Somit sieht der User den Link und die Dateil kann im Hintergrund erstellt werden.

Letztendlich hat man da dummerweise Race Conditions, d.h. der User kann schneller klicken als das die Datei erstellt wird. :?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Montag 15. September 2008, 09:58

Leonidas hat geschrieben:Ich würde im View eine Art Token generieren, was an den User zurückgeschickt wird und gleichzeitig an den Dateigenerator in einem anderen Thread. Somit sieht der User den Link und die Dateil kann im Hintergrund erstellt werden.

Letztendlich hat man da dummerweise Race Conditions, d.h. der User kann schneller klicken als das die Datei erstellt wird. :?
Bin am überlegen wie ich das mit dem Token machen sollte. Ich denke gerade an sowas wie ein Systemaufruf mit & oder sowas in der Art. Mit Python threading habe ich keine Erfahrung. gibt es Befehle wie ich einen Funktionsaufruf im Hintergrund starten kann?

Mit der Race Condition will ich mir eine view erstellen, die den Inhalt des Ordners anzeigt, und somit die fertigen Dateien, wenn eine bestimmte Datei (xyz.log) vorhanden ist. Diese wollte ich dann einfach erstellen lassen wenn mein Script fertig ist. Ansonsten eben sowas wie "Dateien noch nicht ganz fertig, versuchen Sie es in wenigen Minuten noch einmal" oder sowas.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 15. September 2008, 10:12

würmchen hat geschrieben:Bin am überlegen wie ich das mit dem Token machen sollte. Ich denke gerade an sowas wie ein Systemaufruf mit & oder sowas in der Art. Mit Python threading habe ich keine Erfahrung. gibt es Befehle wie ich einen Funktionsaufruf im Hintergrund starten kann?
Klar, geht beides. Mit Prozessen nutzt du einfach subprocess und lässt es asynchron laufen und mit Threads gibt es das Thread und threading Modul. Gerade ``thread.start_new_thread()`` ist, obwohl ich es nicht so besonders mag, sehr einfach zu nutzen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Montag 15. September 2008, 10:30

Damit ich das richtig verstehe, dazu muss ich aber ein ausführbares python Script schreiben, wessen ich mit ARGV oder so Übergabeparameter übergebe. Ich kann nicht in meiner View das erzeugte Objekt und NUR die Funktion in einem extra Thread aufrufen, oder?
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 15. September 2008, 10:44

würmchen hat geschrieben:Damit ich das richtig verstehe, dazu muss ich aber ein ausführbares python Script schreiben, wessen ich mit ARGV oder so Übergabeparameter übergebe.
Genau.
würmchen hat geschrieben:Ich kann nicht in meiner View das erzeugte Objekt und NUR die Funktion in einem extra Thread aufrufen, oder?
Doch. Jetzt mal vorrausgesetzt das ganze ist threadsafe, aber sonst ja.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Montag 15. September 2008, 10:51

Also das ganze sollte Threadsave sein, lesen tue ich Daten aus einer Datenbank, schreiben werde ich dann in einen eigenen Ordner...
Es würde dann ein Thread alle Dateien erstellen.

Hast Du zufällig ein gutes Beispiel für die Arbeit mit Threads? Hatte mal in Java mit Threads programmiert, also Grundkenntnisse sind da. Ich denke ich muss dann ein Threadclasse erzeugen und dieser dann das Objekt übergeben, die Threadklasse ruft dann die Funktion auf, was im Moment die View macht.

Hm, geht es dann direkt weiter in meiner view oder wird dann auch noch auf einen Rückgabewert gewartet oder sowas?
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 15. September 2008, 11:28

würmchen hat geschrieben:Hast Du zufällig ein gutes Beispiel für die Arbeit mit Threads? Hatte mal in Java mit Threads programmiert, also Grundkenntnisse sind da. Ich denke ich muss dann ein Threadclasse erzeugen und dieser dann das Objekt übergeben, die Threadklasse ruft dann die Funktion auf, was im Moment die View macht.
Ich habe dir doch gesagt was du brauchst, jetzt kannst du in der Dokumentation nachschlagen und/oder die Suchfunktion benuten um Beispiele zu finden.
würmchen hat geschrieben:Hm, geht es dann direkt weiter in meiner view oder wird dann auch noch auf einen Rückgabewert gewartet oder sowas?
Auf was für einen Rückgabewert willst du denn warten? Wenn du den Thread synchronisierst, wozu brauchst du ihn dann überhaupt? ;)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Dienstag 18. November 2008, 17:08

Hallo, ich hab erst jetzt wieder Zeit um mich um dieses Problem zu kümmern und wollte jetzt nochmal um Hilfe bitten.

Das mit den Threads funktioniert und ich kann mir einen Link zurück geben lassen.

Ich wollte fragen, ob ich diesen Link gleich in einem neuen Fenster öffnen kann? Sozusagen als popup?

Sollte möglichst beides geschehen, also einmal den Link anzeigen und zum anderen den Link gleich in einem neuen Fenster öffnen.

Danke für eure Hilfe
Antworten