1. ホーム
  2. Django

Django2.2エラー - AttributeError: ''str'' オブジェクトに ''decode'' 属性がない。

2022-02-28 07:46:58
<パス

メソッドの説明

Django 2.2 error-AttributeError: 'str' object has no attribute 'decode' に対する解決策は一時的なもので、より良い解決策はこのメソッドを任意に使用すべきです。

  • エラー報告スニペット

        # Located at /home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/mysql/operations.py 
        # Line 140
        def last_executed_query(self, cursor, sql, params):
            # With MySQLdb, cursor objects have an (undocumented) "_executed"
            # attribute where the exact query sent to the database is saved.
            # See MySQLdb/cursors.py in the source distribution.
            query = getattr(cursor, '_executed', None)
            # print("=========================>>>>>>>>>>", type(query))
            # I added this line myself
            if query is not None:
                query = query.decode(errors='replace')
            return query
    
    
    
  • エラーメッセージ
    また、以下のように見ることができます。 getattr この関数は、型

    str
    (base) [soul@listener one_orm]$ python manage.py makemigrations
    =========================>>>>>>>>> <class 'str'>
    Traceback (most recent call last):
      File "manage.py", line 21, in <module>
        main()
      File "manage.py", line 17, in main
        execute_from_command_line(sys.argv)
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command _line
        utility.execute()
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/core/management/__init__.py", line 375, in execute
        self.fetch_command(subcommand).run_from_argv(self.argv)
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/core/management/base.py", line 323, in run_from_argv
        self.execute(*args, **cmd_options)
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/core/management/base.py", line 364, in execute
        output = self.handle(*args, **options)
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/core/management/base.py", line 83, in wrapped
        res = handle_func(*args, **kwargs)
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/core/management/commands/makemigrations.py", line 101, in handle
        loader.check_consistent_history(connection)
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/migrations/loader.py", line 283, in check_consistent_history
        applied = recorder.applied_migrations()
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/migrations/recorder.py", line 73, in applied_migrations
        if self.has_table():
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/migrations/recorder.py", line 56, in has_table
        return self.Migration._meta.db_table in self.connection.introspection.table_names(self.connection.cursor())
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/base/base.py", line 256, in cursor
        return self._cursor()
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/base/base.py", line 233, in _cursor
        self.ensure_connection()
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/base/base.py", line 217, in ensure_connection
        self.connect()
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/base/base.py", line 197, in connect
        self.init_connection_state()
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 231, in init_connection_state
        if self.features.is_sql_auto_is_null_enabled:
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/utils/functional.py", line 80, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/mysql/features.py", line 82, in is_sql_auto_is_null _enabled
        cursor.execute('SELECT @@SQL_AUTO_IS_NULL')
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/utils.py", line 103, in execute
        sql = self.db.ops.last_executed_query(self.cursor, sql, params)
      File "/home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/mysql/operations.py", line 147, in last_executed_query query
        query = query.decode(errors='replace')
    AttributeError: 'str' object has no attribute 'decode'
    
    
    

コーデックの説明

<ブロッククオート

メモリのユニコード形式をハードディスクのUtf-8形式にエンコードし、その逆処理でデコードされる

  • コードです。 テキストをバイトのストリームに変換する処理。それは Unicode これは、テキストをバイトストリームに変換する処理で、ハードディスクに保存するために特定のフォーマットでエンコードして特定のバイトストリームを生成します(通常はutf-8フォーマット)。
  • デコードする。 ハードディスクに記録されたバイト列をテキストに変換する処理。つまり、特定の形式のバイトの流れ
    Unicode
    
  • 注意事項 メモリに書き込まれた文字は、すべて等しくユニコード化されていますが、ハードディスクに保存したり、ネットワークに基づいて転送したりするときにだけ、入力した文字が英語か中国語かを判断することができます、これは Unicode 他の符号化方式に変換する作業です。
  • decode("utf-8", "ignore") 例外を持つエンコーディングは無視し、有効なエンコーディングのみを表示する。
  • decode("utf-8", "replace") 異常なエンコーディングを置き換えるので、間違ったエンコーディングを見つけるのが比較的簡単になります。

Python3での文字列書式設定

  • 文字列の種類です。
    つまり、通常は str 型のオブジェクトを定義します。Python 3 では str 型のオブジェクトはすべて Unicode なので、str 型のオブジェクトには encode() メソッドだけがあり、decode() メソッドはありません(実行するとエラーが報告されます)。
  • バイト文字列の型
    つまり、byte型のオブジェクトです。str型オブジェクトがencode()メソッドを使って生成したこのタイプのオブジェクトに対して、byteオブジェクトはデコード処理を行い、本当の内容を得ることができるのです

実はこの時点でエラーの原因が分かっているので、次に進みましょう

python3 で getattr() 機能

  • 説明
    getattr()関数は、オブジェクトの属性値を返すために使用されます。

  • 構文

    getattr(object,name,default)
    
    
    
  • パラメータです。

    • object -オブジェクト
    • name -文字列、オブジェクトのプロパティ
    • default -デフォルトの戻り値、このパラメータが提供されない場合、その属性がない場合、AttributeErrorが発生します。
  • 戻り値
    オブジェクトのプロパティ値を返します。

    class People:
      country='China'
      def __init__(self,name):
        self.name=name
     
      def people_info(self):
        print('%s is xxx' %(self.name))
    obj=getattr(People,'country')
    print(obj)
    #return value China
    #obj=getattr(People,'countryaaaaaa')
    #print(obj)
    #returns an error
    # File "/getattr() function.py", line 32, in 
    
    # obj=getattr(People,'countryaaaaaa')
    # AttributeError: type object 'People' has no attribute 'countryaaaaaa'
    obj=getattr(People,'countryaaaaaa',None)
    print(obj)
    # return value None
    
    
    

プログラムの修正

<ブロッククオート

上記のpython3における文字列の知識と getattr 関数の戻り値の型に起因するものであると結論付けることができます。 str いいえ decode() メソッドによって引き起こされる

オプション1

この2行のコードを直接コメントする

# Located at /home/soul/anaconda3/lib/python3.6/site-packages/django/db/backends/mysql/operations.py 
# Line 140
def last_executed_query(self, cursor, sql, params):
    # With MySQLdb, cursor objects have an (undocumented) "_executed"
    # attribute where the exact query sent to the database is saved.
    # See MySQLdb/cursors.py in the source distribution.
    query = getattr(cursor, '_executed', None)
    # if query is not None:
    # query = query.decode(errors='replace')
    return query


オプション2

このオプションは django 1.11のコードとスニペットコメント、このコード追加の正確な意味は、やや不可解です。

しかし、念のため、このような場合に備えて、このページに try メソッドを使用して、別のアノテーションにアクセスすることができます。

def last_executed_query(self, cursor, sql, params):
    # With MySQLdb, cursor objects have an (undocumented) "_executed"
    # attribute where the exact query sent to the database is saved.
    # See MySQLdb/cursors.py in the source distribution.
    query = getattr(cursor, '_executed', None)
    try:
        if query is not None:
            query = query.decode(errors='replace')
        return query
    except:
        return query


まだ終わらないよ!!!

よく知られているのは django はオープンソースのプロジェクトなので、githubでチェックしてみてはいかがでしょうか?

私は、これまで Pull requests 探していた答えが見つからなかったので、djangoプロジェクトのbyディレクトリを探したところ operations.py ファイル

django/django/db/backends/mysql/operations.py


案の定、オープンソースのコミュニティは最高です!!!!

最新のコードでは last_executed_query 関数は以下のように変更されています。

# 11/27/19 at line 157
def last_executed_query(self, cursor, sql, params):
    # With MySQLdb, cursor objects have an (undocumented) "_executed"
    # attribute where the exact query sent to the database is saved.
    # See MySQLdb/cursors.py in the source distribution.
    # MySQLdb returns string, PyMySQL bytes.
    return force_str(getattr(cursor, '_executed', None), errors='replace')

force_str

django/django/utils/encoding.py メソッドが定義されています。 ... class DjangoUnicodeDecodeError(UnicodeDecodeError): def __init__(self, obj, *args): self.obj = obj super(). __init__(*args) def __str__(self): return '%s. you passed in %r (%s)' % (super(). __str__(), self.obj, type(self.obj)) ... def is_protected_type(obj): """Determine if the object instance is of a protected type. Objects of protected types are preserved as-is when passed to force_text(strings_only=True). """ return isinstance(obj, _PROTECTED_TYPES) def force_text(s, encoding='utf-8', strings_only=False, errors='strict'): """ Similar to smart_text, except that lazy instances are resolved to strings, rather than kept as lazy objects. If strings_only is True, don't convert (some) non-string-like objects. """ # Handle the common case first for performance reasons. if issubclass(type(s), str): return s if strings_only and is_protected_type(s): return s try: if isinstance(s, bytes): s = str(s, encoding, errors) else: s = str(s) except UnicodeDecodeError as e: raise DjangoUnicodeDecodeError(s, *e.args) return s ... force_str = force_text 現在のコードと比較すると、48行目に

ローカルコードは

django2.2.6

比較すると、(ローカル環境は force_str )、私のローカルのdjangoのソースコードでは force_text メソッドと operations.py が同じで、それ以外の部分は現在のgithubのコードと同じなので from django.utils.encoding import force_text ... def last_executed_query(self, cursor, sql, params): # With MySQLdb, cursor objects have an (undocumented) "_executed" # attribute where the exact query sent to the database is saved. # See MySQLdb/cursors.py in the source distribution. # MySQLdb returns string, PyMySQL bytes. return force_text(getattr(cursor, '_executed', None), errors='replace') ファイルはgithubと同じです

(base) [soul@listener one_orm]$ python manage.py makemigrations
No changes detected


テストを実行します。

(base) [soul@listener one_orm]$ python manage.py makemigrations
No changes detected


オリーがくれたのは!?

<ブロッククオート

この時点で、問題は解決