【问题标题】:Django Filtering MySQL WarningsDjango 过滤 MySQL 警告
【发布时间】:2010-08-04 19:50:29
【问题描述】:

在你们都指出我之前herehere 我有点不同。因此,在转移到生产服务器后,我开始遇到著名的错误。

django/db/backends/mysql/base.py:86:警告:第 1 行“slug”列的数据被截断

我做的第一件事是在解决问题后开始在谷歌上搜索。为了解决这个问题,我调整了两个模型的 max_length 为 128 ad,然后更新了 SQL 表以匹配它。 但问题仍然存在.. 对我确实解决了问题有点信心,我想我也可以开始过滤掉它们。所以我把它放在了脚本的顶部。

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

我很高兴将其推向生产。你猜怎么着——你猜对了,问题仍然存在。那么现在怎么办。我很快就失去了我确实解决了问题的信心,但仔细检查表明所有 slug 列都是 128 个字符长。此外,如果它长于 128 并且仍然没有,我将 sluggify 包装为错误。所以2个问题:

  1. 我怎样才能确定什么操作 正在标记这个。即在我的哪里 代码是升旗了吗?

  2. 我怎样才能真正过滤掉这些?我的修复不起作用?这真的是 MySQLdb 警告还是 django.db.mysql.base 警告?

感谢和愉快的 Django 黑客攻击!

对于那些对结构有疑问的​​人..

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;

以及相关的models.py。

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

希望对您有所帮助..

【问题讨论】:

  • 此数据可能来自的字段是否有文本限制?
  • 否 - 我在保存时设置 slug。如果长度> 128(但不是......),我会发出警告。
  • 你能把你表的describe(来自生产箱)的输出和你正在使用的模型贴出来吗?
  • 您能否将查询粘贴到生成警告消息的位置?

标签: python django django-models


【解决方案1】:

首先,我强烈建议不要过滤这样的警告:这个错误是由 MySQL 产生的,它绝对意味着你正在丢失数据。

首先要做的是使用 MySQL describe 命令来确保您的数据库列实际上定义为您期望的相同大小:如果您更改列的长度,Django 不支持数据库迁移,所以如果您的 slug 字段比现在短,您需要手动更改表格以设置新长度:

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

如果该字段不是您所期望的,您可以通过更新列长度来解决问题:

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

如果您在 slug 中允许使用 Unicode 字符,这也可以解释为您上面的转储似乎使用 latin1 字符集而不是 UTF-8 - 单个 UTF-8 字符最多可以是 4 个字节数据,这意味着短至 17 个字节的值可能会溢出 VARCHAR(64)

下一个调试步骤是对您正在进行的调用进行简单的变体,以过滤警告以准确找出错误发生的位置:

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

这将使警告变得致命,这将停止你的程序,但更重要的是还会产生一个堆栈跟踪。有了这样的东西,你会看到下面的输出:

#!/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()

没有 simplefilter 调用:

cadams@Io:~ $ python test_warnings.py 
test_warnings.py:5: UserWarning: uhoh
  warnings.warn("uhoh")

使用 simplefilter 调用:

cadams@Io:~ $ 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

【讨论】:

  • 哇 - 谈论复兴!不错的工作!我已经解决了(未能更新此站点)。您提到的是 UTF-8/Latin 问题。找到它真是太棒了。不过这里有很好的提示!
【解决方案2】:

我会编辑我的项目的settings.py 文件,让这种行为发生在我的整个 django 项目中。否则,我可以简单地将它包含在我希望发生这种行为的脚本的一部分中。


引发 MySQL 警告为错误:

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

要忽略而不是引发错误,请将"error" 替换为"ignore"

在 try-except 块中处理它们,例如:

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

【讨论】:

    【解决方案3】:

    有一个类似的问题,但使用不同的模块(例如,导入 floppyforms 时未找到 gis 模块。)这些对我们的应用程序来说确实是多余的,所以我在我们的设置文件中添加了以下内容:

    # Set up warnings filters
    # (action, re-pattern, category)   See warnings module docu.  Python std lib 28.6)
    
    WARNINGS_FILTERS = [
        ("ignore", "Unable to import floppyforms.gis, geometry widgets not available", UserWarning),
        ("ignore", "There are known rendering problems with Cairo <= 1.14.0", UserWarning),
        ("ignore", "@font-face support needs Pango >= 1.38", UserWarning),
    ]
    
    import warnings
    
    for wf in WARNINGS_FILTERS:
        warnings.filterwarnings(*wf)
    

    遍历这样的列表为我提供了一种更简单、更简洁的方式来添加/修改/删除将来的警告。

    注意:每次导入设置时都会有少量的“额外”处理(例如,新工作人员启动),但是,如果append=False(这是默认设置),警告模块将替换现有警告。换句话说,多次导入设置不会导致注册多个相同的过滤器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-23
      • 1970-01-01
      • 1970-01-01
      • 2017-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多