Hallo Leute,
ich arbeite mit unter django und mache dort ein drop table if exist aufruf. die tabelle existiert nicht immer zu diesem zeitpunkt, aber ich bekomme im browser einen fehler 500 und die seite wird nicht angezeigt wegen dem warning das die tabelle nicht existiert.
kann ich die warnings ausschalten?
Ich hab hier eine Seite gefunden wie man die warnings ausstellen soll, aber ich versteh nicht wie ich das in meine view einbau...
http://momentarypause.blogspot.com/2006 ... x-ins.html
drop table if exist warning unter django
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Dieser code vom Blog Eintrag könntest du in deiner settings.py einbauen und dann sollte es gehen:
Wahrscheinlich mußt du aber "Unknown table.*_temp" anpassen, vielleicht: "Unknown table.*"
Man könnte das ganze auch so machen, das alle warnings in einer Datei geschrieben werden. Oder das alle Warnings zum User umgeleitet werden: http://www.djangoproject.com/documentat ... /#messages
In PyLucid leite ich alle Warnungen in die page_msg, somit sieht man die einfach auf der generierten Seite.
Code: Alles auswählen
import warnings
Class Blah:
def supress_warnings():
# I get a warning on "DROP TABLE IF EXISTS" query,
# that the temp table (something_temp) is unknown.
warnings.filterwarnings("ignore", "Unknown table.*_temp")
return
supress_warnings = staticmethod(supress_warnings)
Man könnte das ganze auch so machen, das alle warnings in einer Datei geschrieben werden. Oder das alle Warnings zum User umgeleitet werden: http://www.djangoproject.com/documentat ... /#messages
In PyLucid leite ich alle Warnungen in die page_msg, somit sieht man die einfach auf der generierten Seite.
Hm, also bei mir wird die Warnung nicht unterdrückt.
ich hab es genau so ans Ende der settings.py kopiert und dann noch Class -> class geändert und eben Unknown table.* in dem String geschrieben.
Ich bekomme immer noch die gleiche 500er Errorpage mit dem Hinweis "Unknown table 3_blablubdumdidum"
Muss ich sonst noch irgendwas importieren außer dieses import warnings? Bzw ein Objekt der Klasse erstellen? Mir ist im Moment nicht ganz klar wie dieser Code Schnipsel funktionieren soll.
ich hab es genau so ans Ende der settings.py kopiert und dann noch Class -> class geändert und eben Unknown table.* in dem String geschrieben.
Ich bekomme immer noch die gleiche 500er Errorpage mit dem Hinweis "Unknown table 3_blablubdumdidum"
Muss ich sonst noch irgendwas importieren außer dieses import warnings? Bzw ein Objekt der Klasse erstellen? Mir ist im Moment nicht ganz klar wie dieser Code Schnipsel funktionieren soll.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Also ich weiß nicht ob der sourcecode aus dem Blog überhaupt richtig funktioniert.
Ich hab noch was in den PyLucid sourcen gefunden, eine eigentlich deaktivierter codeblock, kannst du ja mal probieren:
Du könntest bei def showwarning() auch einfach nur mit "pass" nichts machen.
Ich hab noch was in den PyLucid sourcen gefunden, eine eigentlich deaktivierter codeblock, kannst du ja mal probieren:
Code: Alles auswählen
import warnings, logging
# Needs to have the file rights to create/write into this file!
LOGFILE = "PyLucid_warnings.log"
try:
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)s %(message)s',
filename=LOGFILE,
filemode='a'
)
except IOError, err:
raise IOError("Can't setup low level warning redirect: %s" % err)
log = logging.debug
log("PyLucid warnings logging started.")
warning_container = []
def showwarning(message, category, filename, lineno):
msg = unicode(message)
filename = u"..." + filename[-30:]
msg += u" (%s - line %s)" % (filename, lineno)
log(msg)
old_showwarning = warnings.showwarning
warnings.showwarning = showwarning
Also ich bekomm es nicht hin...
Also was der Typ in seinem Blog vorgeschlagen hat war ja nichts weiter wie "irgendeine" neue Funktion die die Warnungen rausfiltert. Die wurde danach "global" verfügbar gemacht. Aber wie soll ich die dann aufrufen. Ich meine, müsste ich dann nicht dann nicht irgendwie mich darum kümmern das nichtmehr showwarnings sondern eben supress_warnings aufgerufen wurde???
Naja, das ist zumindest der Weg den PyLusid geht, oder versteh ich das falsch. Hier geht man hin und überschreibt die Standard Ausgabe eben mit einer neuen.
Diese wird dann mit
warnings.showwarnings = showwarnings
zugewiesen.
Ich hab das so versucht und ich bekomm immer noch Warnmeldungen. Hab auch versucht warnings.showwarnings = supress_warnings, weil das, in meinem Kopf zumindest
, am meisten Sinn gemacht hätte.
Versteh ich da irgendwas falsch?
Code: Alles auswählen
def supress_warnings():
# I get a warning on "DROP TABLE IF EXISTS" query,
# that the temp table (something_temp) is unknown.
warnings.filterwarnings("ignore", "Unknown table.*")
return
#supress_warnings = staticmethod(supress_warnings)
def showwarning(message, category, filename, lineno):
pass
old_showwarning = warnings.showwarning
warnings.showwarning = showwarning
Naja, das ist zumindest der Weg den PyLusid geht, oder versteh ich das falsch. Hier geht man hin und überschreibt die Standard Ausgabe eben mit einer neuen.
Diese wird dann mit
warnings.showwarnings = showwarnings
zugewiesen.
Ich hab das so versucht und ich bekomm immer noch Warnmeldungen. Hab auch versucht warnings.showwarnings = supress_warnings, weil das, in meinem Kopf zumindest

Versteh ich da irgendwas falsch?
Ok, ich hab eben den Fehler gefunden, aber vielleicht kann mir noch Jemand sagen ob ich das jetzt richtig mache, oder was ich besser anders machen sollte....
EDIT: Ich hab sicher etwas falsch gemacht, weil jetzt gibt er keine Fehler mehr aus... :-/
Mein Fehler war gewesen, das ich hätte der warn() Funktion diesen Filter unterschieben müssen. Das hab ich jetzt getan. Nur frag ich mich ob ich das richtig gemacht habe.
Was mich auch noch interessieren würde, wie kann ich die Warnungen dann an das Message System weiterleiten. Dazu brauch ich ja ein requestuser Objekt, was ich aber in der der settings.py nicht wirklich habe.
EDIT:
Ich lese eben nochmal genau die Beschreibung des Moduls warnings und finde folgenden Abschnitt....
Demnach sollte ich doch einfach irgendwo meinen filterwarnings definieren können, und der sollte das dann vorne in die liste einstellen.
warnings.filterwarnings("ignore", "Unknown table.*")
ist jetzt nur die frage, warum es nicht matched
EDIT: Ich hab sicher etwas falsch gemacht, weil jetzt gibt er keine Fehler mehr aus... :-/
Code: Alles auswählen
#to prevent warning messages
def supress_warnings(message, category, stacklevel):
# I get a warning on "DROP TABLE IF EXISTS" query,
# that the temp table (something_temp) is unknown.
warnings.filterwarnings("ignore", "Unknown table.*")
return
#supress_warnings = staticmethod(supress_warnings)
warnings.warn = supress_warnings
Was mich auch noch interessieren würde, wie kann ich die Warnungen dann an das Message System weiterleiten. Dazu brauch ich ja ein requestuser Objekt, was ich aber in der der settings.py nicht wirklich habe.
EDIT:
Ich lese eben nochmal genau die Beschreibung des Moduls warnings und finde folgenden Abschnitt....
http://docs.python.org/lib/warning-functions.htmlfilterwarnings( action[, message[, category[, module[, lineno[, append]]]]])
Insert an entry into the list of warnings filters. The entry is inserted at the front by default; if append is true, it is inserted at the end. This checks the types of the arguments, compiles the message and module regular expressions, and inserts them as a tuple in the list of warnings filters. Entries closer to the front of the list override entries later in the list, if both match a particular warning. Omitted arguments default to a value that matches everything.
Demnach sollte ich doch einfach irgendwo meinen filterwarnings definieren können, und der sollte das dann vorne in die liste einstellen.
warnings.filterwarnings("ignore", "Unknown table.*")
ist jetzt nur die frage, warum es nicht matched
Ok, das mit den warnings konnte ich lösen. Ich hab jetzt warnings.filterwarnings in meine views.py eingetragen und da geht es. Verstehe jetzt nicht warum, sollte doch eigentlich egal sein, an welcher stelle der import ist und wo der Fehler ausgelöst wird, aber nun gut.
@jens
kannst Du mir erklären wie ich jetzt diese Ausgaben umleiten kann in dieses Standard Message System?
@jens
kannst Du mir erklären wie ich jetzt diese Ausgaben umleiten kann in dieses Standard Message System?
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Schau dir mal mein Beispiel mit der Log Datei an. Dabei kannst du in showwarning() statt dem log(msg) sowas machen: user_obj.message_set.create(message=msg):
Schau mal hier: http://www.djangoproject.com/documentat ... /#messages
Die Frage ist, woher kommt das user_obj. Du könntest entweder sowas tun: user_obj = User.objects.get(username="DerAdmin") Dabei ist die Frage, woher kommt der username, aber den könnte man in einer settings Variable stecken. Oder man könnte einfach alle warnings an alle User schicken die is_staff oder is_superuser sind.
Oder du machst dieses ThreadlocalsAndUser zeug um es an den aktuellen User zu schicken, siehe:
http://code.djangoproject.com/wiki/Cook ... alsAndUser
http://www.python-forum.de/topic-14888.html
Schau mal hier: http://www.djangoproject.com/documentat ... /#messages
Die Frage ist, woher kommt das user_obj. Du könntest entweder sowas tun: user_obj = User.objects.get(username="DerAdmin") Dabei ist die Frage, woher kommt der username, aber den könnte man in einer settings Variable stecken. Oder man könnte einfach alle warnings an alle User schicken die is_staff oder is_superuser sind.
Oder du machst dieses ThreadlocalsAndUser zeug um es an den aktuellen User zu schicken, siehe:
http://code.djangoproject.com/wiki/Cook ... alsAndUser
http://www.python-forum.de/topic-14888.html
Also ich hab dann jetzt einfach mal direkt in der View die das mit dem drop table macht die Funktion definiert und hab ja auch in dieser View meinen request.user Aber es geht trotzdem nicht.
Ich hatte auch mal versucht den request mit der Funktion showwarning zu übergeben, aber das geht auch nicht.
Mir kommt es so vor als ob diese showwarning Funktion nicht aufgerufen wird. Auch wenn ich den kompletten Code von Dir verwende wird das Logfile angelegt, Es steht auch die ersten debiggung Message drin, aber die anderen Fehler werden nicht rein geschrieben....
Code: Alles auswählen
def interface(request):
from bif.interface.interface import WebInterface
from bif.interface import output
def showwarning(message, category, filename, lineno):
msg = unicode(message)
filename = u"..." + filename[-30:]
msg += u" (%s - line %s)" % (filename, lineno)
request.user.message_set.create(message=msg)
old_showwarning = warnings.showwarning
warnings.showwarning = showwarning
interface = WebInterface(request.POST['database'],
request.session.get('tablename'))
interface.dropTable()
Mir kommt es so vor als ob diese showwarning Funktion nicht aufgerufen wird. Auch wenn ich den kompletten Code von Dir verwende wird das Logfile angelegt, Es steht auch die ersten debiggung Message drin, aber die anderen Fehler werden nicht rein geschrieben....
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Keine Ahnung. Vielleicht löst nicht wirklich interface.dropTable() die Warnung aus? Evtl. wird das SQL Statements in Wirklichkeit später ausgeführt, Stichwort Transaction?
Das dürfte aber nicht passieren, wenn showwarning in der settings.py geändert wurde. Also in PyLucid bekomme ich MySQL warnings zu sehen. Benutzt du auch MySQL? Eine ganz andere Möglichkeit wäre es, MySQL die Warnings abzugewöhnen. Wie das geht, weiß ich aber nicht.
Generell denke ich aber das es schon der richtige Weg ist. Aus der Doku:
Das dürfte aber nicht passieren, wenn showwarning in der settings.py geändert wurde. Also in PyLucid bekomme ich MySQL warnings zu sehen. Benutzt du auch MySQL? Eine ganz andere Möglichkeit wäre es, MySQL die Warnings abzugewöhnen. Wie das geht, weiß ich aber nicht.
Generell denke ich aber das es schon der richtige Weg ist. Aus der Doku:
showwarning( message, category, filename, lineno[, file])
Write a warning to a file. The default implementation calls formatwarning(message, category, filename, lineno) and writes the resulting string to file, which defaults to sys.stderr. You may replace this function with an alternative implementation by assigning to warnings.showwarning.
Also ich weiß nicht genau woran es liegt, aber ich hab jetzt folgendes getestet.
Funktioniert einwandfrei, schreibt die "This was a warning message" in die Datei, die andere wird unterdrückt.
Hab das ganze jetzt in die settings.py geschrieben, und mir fällt auf, die Date wir neu beim neustarten des runserver Scriptes ausgeführt und anscheinend manchmal mitten drin. Ich bekomm zumindest einmal meine Fehlermeldung in die Datei geschrieben.
Aber alles andere, was einen Fehler im Programm verursacht, wird weiterhin auf std.err geschrieben.
Ich weiß nicht wie das so genau mit den Modulen ist, aber es kann doch eigentlich nicht sein, das jedes Modul nochmal die neue Funktion brauch oder so, ich überschreibe die doch in der settings.py Global...
Oder sind da eventuell mehrere Instanzen parallel?
Code: Alles auswählen
import warnings
import logging
LOGFILE = "error.log"
warnings.filterwarnings('ignore','This is a.*')
logging.basicConfig(level=logging.INFO,
filename=LOGFILE,
filemode='a')
def send_warnings_to_log(message, category, filename, lineno, file=None):
logging.warning('%s:%s: %s:%s' % (filename, lineno, category.__name__, message))
return
old_showwarning = warnings.showwarning
warnings.showwarning = send_warnings_to_log
warnings.warn('This is a warning message')
warnings.warn('This was a warning message')
Hab das ganze jetzt in die settings.py geschrieben, und mir fällt auf, die Date wir neu beim neustarten des runserver Scriptes ausgeführt und anscheinend manchmal mitten drin. Ich bekomm zumindest einmal meine Fehlermeldung in die Datei geschrieben.
Aber alles andere, was einen Fehler im Programm verursacht, wird weiterhin auf std.err geschrieben.
Ich weiß nicht wie das so genau mit den Modulen ist, aber es kann doch eigentlich nicht sein, das jedes Modul nochmal die neue Funktion brauch oder so, ich überschreibe die doch in der settings.py Global...
Oder sind da eventuell mehrere Instanzen parallel?
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Stimmt. Die settings.py kann mehrfach importiert werden. Du kannst allerdings folgendes machen:
von: http://www.thomas-guettler.de/vortraege ... tml#link_8 (code weiter unten)
Code: Alles auswählen
import logging
if not getattr(logging, "set_up_done", None):
...hier das logging einstellen...
logging.set_up_done=True
Das mehrfach importieren würde doch eigentlich kein Problem darstellen. Hauptsache es wird importiert, oder sehe ich das falsch?
Ich versteh auch echt nicht wo das Problem ist.
hab jetzt in allen beteiligten Dateien ein import logging gemacht.
dort lasse ich mir mit logging.info("string") immer den Funktionsnamen ausgeben, wird einwandfrei in die log Datei geschrieben. selbst ein logging.error wird in die datei geschrieben ohne zu meckern.
Einziges Problem ist es noch die Fehler der Datenbank umzuleiten.
Ich denke das einzige Modul das noch nichts von dieser ganzen logging Geschichte weiß ist mysqldb, aber da will ich nicht drin rumschreiben. Letztendlich ist es aber doch mysqldb das den Fehler bzw den Warning verursacht... Oder?
EDIT:
damit ich jetzt nichts falsch verstehe. Diese showwarning Funktion hab ich jetzt nicht mehr drin, die wird ja letztendlich dazu nicht mehr gebraucht, nachdem ich das Logging so definiert habe, oder???
Also ich hab es eben sowohl mit als auch ohne versucht, geht nicht. Ich verzweifel noch.... Würde gerne von dem filterwarning weg kommen und alles wenigstens in eine Datei schreiben...
Ich versteh auch echt nicht wo das Problem ist.
hab jetzt in allen beteiligten Dateien ein import logging gemacht.
dort lasse ich mir mit logging.info("string") immer den Funktionsnamen ausgeben, wird einwandfrei in die log Datei geschrieben. selbst ein logging.error wird in die datei geschrieben ohne zu meckern.
Einziges Problem ist es noch die Fehler der Datenbank umzuleiten.
Ich denke das einzige Modul das noch nichts von dieser ganzen logging Geschichte weiß ist mysqldb, aber da will ich nicht drin rumschreiben. Letztendlich ist es aber doch mysqldb das den Fehler bzw den Warning verursacht... Oder?
EDIT:
damit ich jetzt nichts falsch verstehe. Diese showwarning Funktion hab ich jetzt nicht mehr drin, die wird ja letztendlich dazu nicht mehr gebraucht, nachdem ich das Logging so definiert habe, oder???
Also ich hab es eben sowohl mit als auch ohne versucht, geht nicht. Ich verzweifel noch.... Würde gerne von dem filterwarning weg kommen und alles wenigstens in eine Datei schreiben...
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Jetzt bin ich ein wenig verwirrt. Also wir haben hier zwei Dinge: Das logging und die warning Geschichte. Diese showwarning Funktion ist dazu da, alle warnings nicht auf stderr auszugeben, sondern in die log Datei umzuleiten. Das macht das logging natürlich nicht von alleine 
Also du brauchst in der settings.py nur die warnings einmal in die log Datei um zu leiten. Danach kannst du überall statt log("BlaBla") ein warnig absetzten und die sollten dann in der log Datei landen.
Normalerweise mach MySQLdb das auch. In der /django/db/backends/mysql/base.py
wird bei DEBUG=True das gemacht:
Es werden also alle MySQLdb warnings als Exceptions geworfen.
Wenn ich mir das recht überlege, brauchst du also im Prinzip auch nur das machen:
Aber IMHO ist eine Umleitung besser 
EDIT: Hm! Ich denke das ist auch das Problem: Du biegst die Warnings in der settings.py um. In der /django/db/backends/mysql/base.py werden die MySQLdb warnings allerdings wieder zu Exceptions gemacht, wenn DEBUG=True ist. Ich schätzte mal es überschreibt dann quasi die änderungen in der settings.py Somit funktioniert das so nicht wirklich...

Also du brauchst in der settings.py nur die warnings einmal in die log Datei um zu leiten. Danach kannst du überall statt log("BlaBla") ein warnig absetzten und die sollten dann in der log Datei landen.
Normalerweise mach MySQLdb das auch. In der /django/db/backends/mysql/base.py
wird bei DEBUG=True das gemacht:
Code: Alles auswählen
filterwarnings("error", category=MySQLdb.Warning)
Wenn ich mir das recht überlege, brauchst du also im Prinzip auch nur das machen:
Code: Alles auswählen
filterwarnings("ignore", category=MySQLdb.Warning)

EDIT: Hm! Ich denke das ist auch das Problem: Du biegst die Warnings in der settings.py um. In der /django/db/backends/mysql/base.py werden die MySQLdb warnings allerdings wieder zu Exceptions gemacht, wenn DEBUG=True ist. Ich schätzte mal es überschreibt dann quasi die änderungen in der settings.py Somit funktioniert das so nicht wirklich...
Damit kannst Du gut recht haben. Noch dazu nehme ich nicht das Paket mysql sindern mysqldb, also nichts mit django.
Das werde ich dann gleich mal ändern...
Als zweites könnte ich hingehen und könnte in der base.py einfach ein
setzen, dann sollte der filterwarnings ans ende gesetzt werden und wird somit auf jeden fall von dem vorher oder nachher von mir gesetzten überschrieben... Weil in der Beschreibung steht ja das die filter in einem tupel sind, das von vorne nach hinten abgearbeitet wird und welches weiter vorne ist zählt...
Ich versuch das jetzt mal....
EDIT:
Ok, ich glaub da hab ich was falsch verstanden. mysql kann ich also nicht nutzen. Aber könnte das das problem sein, das ich das normale MySQLdb Modul nutze?
EDIT2:
Ok, also ich hab das jetzt so gemacht, dass der Filter in base.py mit "append=True" gesetzt wird. Resultat ist, schreibe ich keine Filter mehr in der settings.py wird wieder eine Exception geworfen. Wenn ich jedoch jetzt dort einen filter definiere, dann wird dieser vor dem in der base.py ausgewertet und es scheint zu funktionieren...
Jetzt versuch ich das alles noch in das message System einzubauen, damit dann bestimmte user solche Meldungen auch angezeigt bekommen.
Das werde ich dann gleich mal ändern...
Als zweites könnte ich hingehen und könnte in der base.py einfach ein
Code: Alles auswählen
filterwarnings("error", category=MySQLdb.Warning, append=True)
Ich versuch das jetzt mal....
EDIT:
Ok, ich glaub da hab ich was falsch verstanden. mysql kann ich also nicht nutzen. Aber könnte das das problem sein, das ich das normale MySQLdb Modul nutze?
EDIT2:
Ok, also ich hab das jetzt so gemacht, dass der Filter in base.py mit "append=True" gesetzt wird. Resultat ist, schreibe ich keine Filter mehr in der settings.py wird wieder eine Exception geworfen. Wenn ich jedoch jetzt dort einen filter definiere, dann wird dieser vor dem in der base.py ausgewertet und es scheint zu funktionieren...
Jetzt versuch ich das alles noch in das message System einzubauen, damit dann bestimmte user solche Meldungen auch angezeigt bekommen.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Noch dazu dass mehrfach importieren so gesehen auch nicht geht. Wenn man mittels ``import`` ein Modul aus mehreren Quelldateien importiert, wird es nur beim ersten Mal ausgeführt (also der Modulcode), beim zweiten Import bekommt man lediglich eine zweite Referenz auf das bereits importierte Modul.würmchen hat geschrieben:Das mehrfach importieren würde doch eigentlich kein Problem darstellen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice