drop table if exist warning unter django

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

Dienstag 19. August 2008, 15:51

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
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 19. August 2008, 16:27

Dieser code vom Blog Eintrag könntest du in deiner settings.py einbauen und dann sollte es gehen:

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)
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.

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 20. August 2008, 09:02

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.
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 20. August 2008, 10:02

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:

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
Du könntest bei def showwarning() auch einfach nur mit "pass" nichts machen.

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 20. August 2008, 10:57

Also ich bekomm es nicht hin...

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
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?
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Mittwoch 20. August 2008, 11:07

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... :-/

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
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....
filterwarnings( 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.
http://docs.python.org/lib/warning-functions.html


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
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Mittwoch 20. August 2008, 12:19

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?
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 21. August 2008, 08:12

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

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

Donnerstag 21. August 2008, 11:25

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.

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()
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....
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 21. August 2008, 11:37

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:
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.

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

Donnerstag 21. August 2008, 12:59

Also ich weiß nicht genau woran es liegt, aber ich hab jetzt folgendes getestet.

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')
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?
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 21. August 2008, 13:10

Stimmt. Die settings.py kann mehrfach importiert werden. Du kannst allerdings folgendes machen:

Code: Alles auswählen

import logging
if not getattr(logging, "set_up_done", None):

    ...hier das logging einstellen...

    logging.set_up_done=True
von: http://www.thomas-guettler.de/vortraege ... tml#link_8 (code weiter unten)

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

Donnerstag 21. August 2008, 13:45

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...
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 21. August 2008, 14:13

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:

Code: Alles auswählen

filterwarnings("error", category=MySQLdb.Warning)
Es werden also alle MySQLdb warnings als Exceptions geworfen.

Wenn ich mir das recht überlege, brauchst du also im Prinzip auch nur das machen:

Code: Alles auswählen

filterwarnings("ignore", category=MySQLdb.Warning)
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...

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

Donnerstag 21. August 2008, 14:33

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

Code: Alles auswählen

filterwarnings("error", category=MySQLdb.Warning, append=True)
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.
Antworten