0

私はdjango-nonrelベースのアプリを作成しており、Djangoが提供する管理ビュー機能を使用しています。

私は2つのモデルの間に欲しいのですが、Many-to-many relationshipこのために、私はListField内部で見つけたものを使用していますdjangotoolbox.fields

カスタムフォームフィールドを提供するために、この質問で説明されているように、ListFieldを別のクラスModelListFieldでオーバーライドしました。これは、formfield関数をオーバーライドしてMultipleChoiceFieldフォームウィジェットを返します。

ビュー部分は正常に動作しますが、sqlite3バックエンドを使用してモデルを保存できません。

2つのモデル(メモとタグ間の標準的な多対多の関係)を想定します

from django.db import models

class Tag(models.Model):
    name = models.CharField(max_length=255)

class Note(models.Model):
    tags = ModelListField(db.ForeignKey(Tag))

これらの変更により、メモの追加ページが管理インターフェースに正しく表示されますが、メモを保存しようとすると、次の例外が発生します。

InterfaceError, Error binding parameter 0 - probably unsupported type.  
inside django\db\backends\sqlite3\base.py in execute, line 234

行234は次のようになります。

class SQLiteCursorWrapper(Database.Cursor):
    """
    Django uses "format" style placeholders, but pysqlite2 uses "qmark" style.
    This fixes it -- but note that if you want to use a literal "%s" in a query,
    you'll need to use "%%s".
    """
    def execute(self, query, params=()):
        query = self.convert_query(query)
        try:
234 ---->           return Database.Cursor.execute(self, query, params)
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        except Database.DatabaseError, e:
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

そして、呼び出しに渡されるクエリとパラメータは次のとおりです。

query: 'INSERT INTO "note" ("tags") VALUES (?)'  
params: [1, 2, 3]
where 1, 2, 3 are pk of three tag fields in database.

モデルを作成するとき、タグのCOLUMNTYPEを「ListField」として指定します。つまりCREATEテーブルのSQLクエリは次のとおりです。

CREATE TABLE "notes" (
    "id" integer NOT NULL PRIMARY KEY,
    "tags" ListField NOT NULL
)

データベースクエリは、リスト[1,2,3]が表示されたら、barfsの上で呼び出しを実行します。smart_unicode(list)リストの代わりに、リストを文字列として、または文字列として渡そうとしましたが、リストを予期しているため、検証中に(get_db_prep_valueで)エラー"1 2 3"がスローされます。ListField

上記で呼び出すリストオブジェクトを渡すことが正しいかDatabase.Cursor.execute、ListFieldがリストを正しく予期しているために何かが欠落しているかどうかがわかりませんが、データベースに書き込むときに、誰かがこのリストを文字列などに変換する必要がありますか?

ListFieldの使い方の良い例はありません:-(長くて退屈な説明を読んでくれてありがとう。

4

1 に答える 1

0

データベースに保存するために正しい形式でデータを準備するのはget_db_prep_saveの責任であることがわかりました。そのため、ModelListFieldで、get_db_prep_saveをオーバーライドし、それを文字列に変換して、「サポートされていないタイプ」エラーを修正します。

def get_db_prep_save(self, value, connection):
    retval = super(ModelListField, self).get_db_prep_save(value)
    return unicode(retval)

また、SelectWidgetでpk>10のタグが選択されて表示されないという問題が発生しました。django-non 1.3の内部では、以下の関数にevalを追加する必要がありました。

class Select(Widget):
    def render_options(self, choices, selected_choices):
        **if(type(selected_choices) != list):
            selected_choices = eval(selected_choices)**

これが行われたのは、render_optionがlistを文字列として呼び出したためです。つまり[1,2,3]ではなく "[1,2,3]"であり、evalを使用して文字列をリストに戻しました。これら2つが関連しているか、後者の問題がdjango-nonrelのバグであるかはわかりません。

dragonxが言ったように、sqlite3とdjango-nonrelでテストするのは良い考えではないかもしれません。すぐにバックエンドを変更します。

于 2013-02-23T21:05:12.217 に答える