2010-08-04 11 views
8

Prima che tutti mi punti a here e here mio un po 'diverso. Così ho iniziato a ricevere il famoso errore dopo aver spostato il mio server di produzione.Django Filtering MySQL Avvisi

Django/db/backend/mysql/base.py: 86: Attenzione: I dati troncati per la colonna 'slug' alla riga 1

La prima cosa che ho fatto è stato iniziare googling questo dopo ho risolto il problema. Per risolvere questo problema, ho ottimizzato entrambi i modelli per avere una lunghezza massima di 128 annunci, quindi ho aggiornato le tabelle SQL per abbinarlo. Ma il problema persisteva .. Abbastanza sicuro di aver effettivamente risolto il problema, ho pensato che avrei anche iniziato a filtrarli. Quindi in cima alla mia sceneggiatura l'ho inserito.

# Get rid of the MySQLdb warnings 
import warnings 
import MySQLdb 
with warnings.catch_warnings(): 
    warnings.filterwarnings("ignore", category=MySQLdb.Warning) 

E ho fortunatamente spinto questo alla produzione. Indovina, hai indovinato, il problema è rimasto. E ora. Sto rapidamente perdendo la fiducia che in effetti ho risolto il problema, ma un doppio controllo di ciò mostra che tutte le colonne di slug sono lunghe 128 caratteri. Inoltre ho spostato l'errore a errore se è più lungo di 128 e ancora nulla. Quindi 2 domande:

  1. Come posso inchiodare quale operazione è segnalazione. cioè dove nel mio codice viene issata la bandiera?

  2. Come è possibile filtrarli? La mia correzione non funziona? Si tratta davvero di un avviso MySQLdb o di un avviso django.db.mysql.base?

Grazie e felice hacking di Django!

Per coloro che hanno domande sulla struttura ..

CREATE TABLE `people_employee` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(100) DEFAULT NULL, 
    `email` varchar(75) DEFAULT NULL, 
    `location_id` varchar(100) DEFAULT NULL, 
    `jpeg` longtext, 
    `first_name` varchar(100) DEFAULT NULL, 
    `last_name` varchar(100) DEFAULT NULL, 
    `maildomain` varchar(32) DEFAULT NULL, 
    `mailserver` varchar(32) DEFAULT NULL, 
    `mailfile` varchar(64) DEFAULT NULL, 
    `contractor` tinyint(1) NOT NULL, 
    `temporary` tinyint(1) NOT NULL, 
    `formal_name` varchar(100) DEFAULT NULL, 
    `nickname` varchar(32) DEFAULT NULL, 
    `cell_phone` varchar(32) DEFAULT NULL, 
    `office_phone` varchar(32) DEFAULT NULL, 
    `other_phone` varchar(32) DEFAULT NULL, 
    `fax` varchar(32) DEFAULT NULL, 
    `assistant_id` int(11) DEFAULT NULL, 
    `supervisor_id` int(11) DEFAULT NULL, 
    `is_supervisor` tinyint(1) NOT NULL, 
    `department_id` varchar(100) DEFAULT NULL, 
    `division_id` varchar(100) DEFAULT NULL, 
    `section_id` varchar(100) DEFAULT NULL, 
    `job_classification_id` varchar(100) DEFAULT NULL, 
    `functional_area_id` varchar(100) DEFAULT NULL, 
    `position_id` varchar(100) DEFAULT NULL, 
    `notes_url` varchar(200) DEFAULT NULL, 
    `ldap_active` tinyint(1) NOT NULL, 
    `notes_active` tinyint(1) NOT NULL, 
    `created_at` datetime NOT NULL, 
    `last_update` datetime NOT NULL, 
    `is_active` tinyint(1) NOT NULL, 
    `site_id` int(11) NOT NULL, 
    `slug` varchar(128) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `slug` (`slug`), 
    KEY `people_employee_location_id` (`location_id`), 
    KEY `people_employee_assistant_id` (`assistant_id`), 
    KEY `people_employee_supervisor_id` (`supervisor_id`), 
    KEY `people_employee_department_id` (`department_id`), 
    KEY `people_employee_division_id` (`division_id`), 
    KEY `people_employee_section_id` (`section_id`), 
    KEY `people_employee_job_classification_id` (`job_classification_id`), 
    KEY `people_employee_functional_area_id` (`functional_area_id`), 
    KEY `people_employee_position_id` (`position_id`), 
    KEY `people_employee_site_id` (`site_id`) 
) ENGINE=MyISAM AUTO_INCREMENT=1429 DEFAULT CHARSET=latin1; 

E la models.py rilevante.

slug = models.SlugField(max_length=128, editable=False, unique=True) 

Speranza che aiuta ..

+0

sono il campo (s) questi dati possono provenire da hanno limiti di testo imposto? –

+0

No - Sto impostando lo slug al salvataggio. Sto spingendo un avvertimento se la lunghezza è> 128 (ma non è ..). – rh0dium

+0

Puoi pubblicare l'output di 'describe' della tabella (dalla casella di produzione) e il modello che stai utilizzando? –

risposta

3

In primo luogo, vorrei vivamente contro gli avvertimenti di filtraggio come questo: questo errore è generato da MySQL e significa assolutamente che si stanno perdendo i dati.

La prima cosa da fare sarebbe usare il comando MySQL Descrive per assicurarsi che la colonna del tuo database sia effettivamente definita alla stessa dimensione che ti aspetti: Django non ha supporto per le migrazioni del database se cambi la lunghezza di una colonna quindi se il vostro campo slug era sempre più brevi di quanto lo sia ora avresti bisogno di modificare manualmente la tabella per impostare la nuova lunghezza:

mysql> DESCRIBE my_table slug; 
+-------+--------------+------+-----+---------+-------+ 
| Field | Type   | Null | Key | Default | Extra | 
+-------+--------------+------+-----+---------+-------+ 
| slug | varchar(255) | NO | UNI | NULL |  | 
+-------+--------------+------+-----+---------+-------+ 
1 row in set (0.00 sec) 

Se questo campo non era quello che vi aspettavate si può semplicemente risolvere il problema aggiornamento della lunghezza della colonna:

mysql> ALTER TABLE my_table MODIFY slug VARCHAR(255) NOT NULL; 

Se si autorizzano caratteri Unicode nelle lumache, ciò potrebbe anche spiegarlo come il vostro dump sopra sembra utilizzare il set di caratteri latin1 anziché UTF-8 - un singolo carattere UTF-8 può avere fino a 4 byte di dati, ovvero un valore meno di 17 byte potrebbe traboccare un VARCHAR(64).

passo Un successivo debug è una semplice variante della chiamata si sta facendo filtrare le avvertenze per capire esattamente dove i vostri errori stanno accadendo:

warnings.simplefilter("error", category=MySQLdb.Warning) 

Questo renderà la fatale avvertimento, che fermare il vostro programma, ma soprattutto produrrà anche uno stacktrace. Con qualcosa come questo, si vedrà l'uscita di seguito:

#!/usr/bin/env python 
import warnings 

def foo(): 
    warnings.warn("uhoh") 

def bar(): 
    foo() 

def main(): 
    warnings.simplefilter("error", UserWarning) 
    bar() 

if __name__ == "__main__": 
    main() 

Senza la chiamata simplefilter:

[email protected]:~ $ python test_warnings.py 
test_warnings.py:5: UserWarning: uhoh 
    warnings.warn("uhoh") 

Con la chiamata simplefilter:

[email protected]:~ $ python test_warnings.py 
Traceback (most recent call last): 
    File "test_warnings.py", line 15, in <module> 
    main() 
    File "test_warnings.py", line 12, in main 
    bar() 
    File "test_warnings.py", line 8, in bar 
    foo() 
    File "test_warnings.py", line 5, in foo 
    warnings.warn("uhoh") 
UserWarning: uhoh 
+0

Wow - Parla di un risveglio! Bel lavoro! L'avevo già risolto (non è riuscito ad aggiornare questo sito). Era il numero di UTF-8/latino che hai menzionato. Che PITA era trovarlo. Ottimi suggerimenti qui però! – rh0dium

1

vorrei modificare il mio progetto settings.py file per lasciare che questo comportamento si verifichi in tutto il mio progetto di Django. Altrimenti, potrei semplicemente includerlo in una parte dello script in cui voglio che questo comportamento si verifichi.


avvertenze Sollevare MySQL come errori:

import warnings, MySQLdb 
warnings.filterwarnings('error', category=MySQLdb.Warning) 

di ignorare invece di sollevare un errore, sostituire "error" con "ignore".

gestirli in un try-except blocco simile:

try: 
    # a MySQL DB operation that raises a warning 
    # for example: a data truncated warning 
except Warning as a_warning: 
    # do something here