0

実際に SQL リレーションを使用せずに、多対多のリレーションシップを使用して MyModel を AnotherModel にリンクしたいと考えています。代わりに、AnotherModel pks のリストを MyModel の列に格納し、カスタム Field で QuerySet への変換を処理させたいと考えています。 (またはインスタンスのリスト) と、AnotherModel から MyModel への逆の関係。

すでにそれを行った人を知っていますか、または簡単な方法で行うためのヒントはありますか? 私はそれを自分で実装し始めましたが、ManyToManyField の動作を完全に実装することがどれほど複雑になるかを理解し始めています: 私はまだ Django にかなり慣れていないので、適切に行うには枠組み。

これまでのところ、私はこれを持っています:

class InlineManyToManyField(models.CharField):
    __metaclass__ = models.SubfieldBase

    def __init__(self, other_model, *args, **kwargs):
        try:
            assert not other_model._meta.abstract, "{0} cannot define a relation with abstract class {0}".format(
                self.__class__.__name__, to._meta.object_name)
        except AttributeError:
            assert isinstance(other_model, basestring), "{0}({1}) is invalid. First parameter to InlineManyToManyField must be either a model, a model name, or the string self".format(
                self.__class__.__name__,unicode(other_model))
        kwargs['max_length'] = kwargs.get('max_length', 255)
        kwargs['blank'] = kwargs.get('blank', True)
        self.other_model = other_model
        self.token = kwargs.pop('token', ' ')
        super(InlineManyToManyField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        if not value: return
        if isinstance(value, basestring):
            pk_list = value.split(self.token)
            pk_list.pop(0)
            pk_list.pop()
            value = self.other_model._default_manager.filter(pk__in=pk_list)
        return value

    def get_db_prep_value(self, value, connection, prepared=False):
        if not value: return
        pk_list = [item.pk for item in value]
        pk_list.sort()
        return self.token + self.token.join(unicode(pk) for pk in pk_list) + self.token

    def contribute_to_class(self, cls, name):
        super(InlineManyToManyField, self).contribute_to_class(cls, name)
        if isinstance(self.other_model, basestring):
            def resolve_through_model(field, model, cls):
                field.other_model = model
            add_lazy_relation(cls, self, self.other_model, resolve_through_model)

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)

    def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):
        if lookup_type in ('contains', 'icontains'):
            if isinstance(value, self.other_model):
                value = value.pk
            return ["%{0}{1}{0}%".format(self.token, connection.ops.prep_for_like_query(value))]
        return super(InlineManyToManyField, self).get_db_prep_lookup(
            lookup_type, value, connection=connection, prepared=prepared)

そして、これが私がそれを使用する方法です:

class MyModel(models.Model):
    anotherlist = InlineManyToManyField(AnotherModel, token=':')

mymodel テーブルに pk=1 と anotherlist=":1:2:3:" の行が含まれている場合、次のようにできます。

>>> m = MyModel.objects.get(pk=1)
>>> m.anotherlist
[<AnotherModel: 1>, <AnotherModel: 2>, <AnotherModel: 3>]
>>> MyModel.objects.filter(anotherlist__contains=2)
[<MyModel: 2>]

次に追加したいのは逆の関係です。たとえば、上記の「contains」コードを使用して、AnotherModel インスタンスに mymodel_set を設定したいのですが、django/db/ ですべてがどのように機能するかを理解するのに苦労していますモデル/フィールド/related.py :)

それで、私がそれに取り組む前に、どこかで似たようなものに出くわしましたか、それともすでに似たようなものを自分で書いたことがありますか?

4

2 に答える 2

1

うーん...なぜ?そして..しないでください!一般的なすべての SQL データベースは、非常にうまくスケーリングします。内部結合を恐れる必要はありません!..大丈夫です!

あなたがやろうとしていることは少し面倒です...それはさておき、AnotherModelインスタンスを削除するとどうなりますか? 文字列 ID のすべての MyModel テーブルをスキャンしますか? Django 5.6.6.1 が出てきて何か互換性がない場合はどうなりますか? リライト?管理モジュールとそこにある意味/変更についても考えてください!

最初からほんの少しのパフォーマンスにこだわりすぎないでください。壊れている場合は修正し、そうでない場合はテストしてください!

アプリのアーキテクチャにより多くの時間を投資すれば、うまくいきます!

あなたの質問に答えるには:いいえ、私もそのようなことを考えて検索しますが、役に立つものは何も見つかりませんでした!

于 2011-07-28T17:24:56.673 に答える