2

Django 1.4.2 / Python 2.7.3 /MySQL5.5.28サイトを実行しています。このサイトの機能の1つは、管理者がサーバーに電子メールを送信できることです。サーバーは、電子メールを解析してDBに投げ込むprocmailを介してPythonスクリプトを呼び出します。私はこのサイトの2つのバージョン(開発サイトと本番サイト)を管理しています。両方のサイトは異なるが同一のvitualenvsを使用しています(念のため、両方を削除し、すべてのパッケージを再インストールしました)。

奇妙な問題が発生しています。まったく同じスクリプトが開発サーバーで成功し、本番サーバーで失敗します。このエラーで失敗します:

...django/db/backends/mysql/base.py:114: Warning: Incorrect string value: '\x92t kno...' for column 'message' at row 1

私はDjangoが抱えるUnicodeの問題をよく知っており、このエラーについてSOにたくさんの質問があることを知っていますが、最初からデータベースをUTF-8としてセットアップするようにしました。

mysql> show variables like "character_set_database";
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| character_set_database | utf8  |
+------------------------+-------+
1 row in set (0.00 sec)

mysql> show variables like "collation_database";
+--------------------+-----------------+
| Variable_name      | Value           |
+--------------------+-----------------+
| collation_database | utf8_general_ci |
+--------------------+-----------------+
1 row in set (0.00 sec)

さらに、各列に独自の文字セットを含めることができることは知っていますが、message実際にはその列はUTF-8です。

mysql> show full columns in listserv_post;
+------------+--------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+
| Field      | Type         | Collation       | Null | Key | Default | Extra          | Privileges                      | Comment |
+------------+--------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+
| id         | int(11)      | NULL            | NO   | PRI | NULL    | auto_increment | select,insert,update,references |         |
| thread_id  | int(11)      | NULL            | NO   | MUL | NULL    |                | select,insert,update,references |         |
| timestamp  | datetime     | NULL            | NO   |     | NULL    |                | select,insert,update,references |         |
| from_name  | varchar(100) | utf8_general_ci | NO   |     | NULL    |                | select,insert,update,references |         |
| from_email | varchar(75)  | utf8_general_ci | NO   |     | NULL    |                | select,insert,update,references |         |
| message    | longtext     | utf8_general_ci | NO   |     | NULL    |                | select,insert,update,references |         |
+------------+--------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+
6 rows in set (0.00 sec)

なぜ私がこのエラーが発生するのか誰かが知っていますか?なぜそれは本番構成では発生しますが、開発構成では発生しませんか?

ありがとう!

[編集1]
明確にするために、データも同じです。サーバーに1通のメールを送信するとprocmailが送信します。.procmailrcは次のようになります。

VERBOSE=off
:0
{
    :0c
    | <path>/dev/ein/scripts/process_new_mail.py dev > outputdev

    :0
    | <path>/prd/ein/scripts/process_new_mail.py prd > outputprd
}

process_new_mail.pyのコピーは2つありますが、これは、2つの別々の環境を維持できるようにバージョン管理されているためです。2つの出力ファイル(受信したメッセージを含む)を比較すると、それらは同一です。

[編集2]devとprdの両方の構成が失敗していることを実際に発見しました。違いは、dev configがサイレントに失敗することです(おそらくDEBUG設定に関係しているのでしょうか?)。問題は、メッセージの1つにいくつかのユニコード文字があり、Djangoが何らかの理由でそれらを窒息させていることです。私は進歩しています...

メッセージをASCIIおよびUTF-8として明示的にエンコードするようにコードを編集しようとしましたが、それでも機能しません。でも、近づいています。

4

1 に答える 1

1

それを私が直した!問題は、文字セットに関して電子メールを正しく解析していなかったことです。私の固定メール解析コードは、この投稿この投稿からのものです:

#get the charset of an email
#courtesy http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual-email-with-python/
def get_charset(message, default='ascii'):
    if message.get_content_charset():
        return message.get_content_charset()

    if message.get_charset():
        return message.get_charset()

    return default

#courtesy https://stackoverflow.com/questions/7166922/extracting-the-body-of-an-email-from-mbox-file-decoding-it-to-plain-text-regard
def get_body(message):
    body = None

    #Walk through the parts of the email to find the text body.
    if message.is_multipart():
        for part in message.walk():
            #If part is multipart, walk through the subparts.
            if part.is_multipart():
                for subpart in part.walk():
                    if subpart.get_content_type() == 'text/plain':
                        #Get the subpart payload (i.e., the message body).
                        charset = get_charset(subpart, get_charset(message))
                        body = unicode(subpart.get_payload(decode=True), charset)
            #Part isn't multipart so get the email body.
            elif part.get_content_type() == 'text/plain':
                charset = get_charset(subpart, get_charset(message))
                body = unicode(part.get_payload(decode=True), charset)
    #If this isn't a multi-part message then get the payload (i.e., the message body).
    elif message.get_content_type() == 'text/plain':
        charset = get_charset(subpart, get_charset(message))
        body = unicode(message.get_payload(decode=True), charset)

    return body

助けてくれてありがとう!

于 2012-11-20T20:15:02.637 に答える