1

更新定義する理由がありget_prep_value()、そうすることでDjangoのフィールドの使用が改善されることがわかりました。ラッパークラスを取り除くこともできました。これらすべてにより、最終的に、__getattribute__ implementation with the data model, which was annoying. So, apart from Django callingto_python() `を非常に頻繁に削除できるようになりました。これで、私が見る限りは元気になりました。/アップデート

ある朝、目を覚ますと、Python2.6.8でDjango1.4.2とDjangoRESTFramework2.1.2を使用していることに気づきます。そしてねえ、物事は間違いなく悪化する可能性があります。このDjango管理者の魔法は、簡単に指定できるリレーショナルデータモデルのフォームを提供し、データベースの編集部分を維持できるようにします。RESTful URLの背後にあるビジネスロジックは、必要に応じて編集データと特定のデータベーステーブルの両方にアクセスします。また、自動生成されたレコードの一部にミニワークフローが必要なため、Django管理者に表示されます。 。

ちょっと待って。これらのバイナリフィールドはまだBINARYとして実装されていません。それらはVARCHARSです。後で使用するために、それをToDoリストに追加しました。そして後で今です。

さて、テーブルサイズが小さく、最適化が必ずしも効果を発揮しない、write-once-read-many-timesのケースがあります。ただし、別のケースでは、テーブル内のINSERTとDELETEが頻繁に発生するため、ストレージとパフォーマンスの両方が無駄になります。

それで、あなたは何が欲しいですか?DBとDjangoの間の明確なマッピング。DBはBINARYを格納し、Djangoは2倍の長さの16進文字列を処理します。達成するのはそれほど難しいことではありませんか?

Webを検索して、VARCHARの代わりにCHARが必要な人、BLOBが必要な人を見つけると、人によって少し違ったやり方をしているようです。最後に、VARCHAR->CHARの場合が正式に処理されるカスタムモデルフィールドの記述に行き着きます。したがって、この情報を使用することにします。

、、およびで始まると__init__()、これはめったに呼び出されないことに気付き、 Djangoが以前に呼び出したことがあったとしても、Djangoが呼び出すようになった図にのみ追加します。ページ上の他の提案が突然わかり始めたので、データをクラスにラップして、への繰り返しの呼び出しからデータを保護できるようにします。また、への提案に従い、を実装します。db_type()to_python()to_python()__metaclass__ = models.SubfieldBaseto_python()to_python()Put a __str__() or __unicode__() method on the class you're wrapping up as a fieldget_prep_value()

結果のコードは期待どおりに機能しませんが、これまでget_prep_value()呼び出されなかったことに気付くことが1つあります。そのため、今のところコードを削除しています。あなた理解していることは、Djangoが一貫strしてDBとunicode管理者からを取得しているように見えることです。これはクールで、最終的にはこのようなものになります(実際には本質に要約されています)。

class MyHexWrappeer(object):
    def __init__(self, hexstr):
        self.hexstr = hexstr
    def __len__(self):
        return len(self.hexstr)
    def __str__(self):
        return self.hexstr

class MyHexField(models.CharField):
    __metaclass__ = models.SubfieldBase
    def __init__(self, max_length, *args, **kwargs):
        assert(max_length % 2 == 0)
        self.max_length = max_length
        super(MyHexField, self).__init__(max_length=max_length, *args, **kwargs)
    def db_type(self, connection):
        return 'binary(%s)' % (self.max_length // 2)
    def to_python(self, data):
        if isinstance(data, MyHexWrapper): # protect object
            return data
        if isinstance(data, str): # binary string from DB side
            return MyHexWrapper(binascii.b2a_hex(data))
        if isinstance(data, unicode): # unicode hex string from admin
            return MyHexWrapper(data)

そして...それは機能しません。もちろん、その理由は、MyHexWrapperDjango自体を含むすべてのソースからオブジェクトを作成するための信頼できる方法を見つけたものの、逆方向のパスが明らかに欠落しているためです。上記の発言から、Djangoが管理者を呼び出しstr()てDBの方向に向かっていると考えていました。しかし、上記を追加すると、呼び出されることはなく、スタックします。unicode()get_prep_value()get_prep_value()

それはできませんよね?だからあなたは簡単に諦めたくないのです。そして突然、あなたはこの1つの厄介な考えを思いつき、あなたはテストを行っています、そしてそれはうまくいきます。そして、あなたはあなたが笑うべきか泣くべきかを知りません。

だから今、あなたはこの修正を試してみて、信じられないかもしれませんが、それはうまくいきます。

class MyHexWrapper(object):
    def __init__(self, hexstr):
        self.hexstr = hexstr
    def __len__(self):
        return len(self.hexstr)
    def __str__(self): # called on its way to the DB
        return binascii.a2b_hex(self.hexstr)
    def __unicode__(self): # called on its way to the admin
        return self.hexstr

それはうまくいきますか?そうですね、RESTful URLのように、コードでそのようなフィールドを使用する場合は、正しい種類の文字列があることを確認する必要があります。それは規律の問題です。

しかし、それでもほとんどの場合しか機能しません。そのようなフィールドを主キーにすると、Djangoが電話をかけ、 「今日」が使用するquote(getattr())と主張する情報源を見つけたので、確認できません。でも、ここまで来たら、それは深刻な障害ではありませんね。getattr()unicode()

class MyModel((models.Model):
    myhex = MyHexField(max_length=32,primary_key=True,editable=False)
    # other fields
    def __getattribute__(self, name):
        if (name == 'myhex'):
            return unicode(super(MyModel, self).__getattribute__(name))
        return super(MyModel, self).__getattribute__(name)

チャームのように機能します。ただし、今は身を乗り出して、ソリューション全体を検討します。そして、それがあなたが参照したドキュメントからの逸脱であり、あなたが意図していなかったドキュメント化されていないまたは内部の動作特性を使用していること、そしてエラーが発生しやすく、開発者にとって使い勝手が悪いことを示していることを理解するのは仕方ありません実装して従わなければならないもののやや分散した性質。

では、どうすれば目的をよりクリーンな方法で達成できるでしょうか。このマッピングを配置する必要があるDjangoにフックと魔法の別のレベルはありますか?

お時間をいただきありがとうございます。

4

0 に答える 0