0

我想在不实际使用 SQL 关系的情况下使用多对多关系将 MyModel 链接到 AnotherModel:相反,我想将 AnotherModel pk 列表存储在 MyModel 的列中,并让自定义字段处理转换为 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>]

接下来我想添加的是反向关系:我希望在 AnotherModel 实例上使用 mymodel_set,例如使用上面的“包含”代码,但我很难理解 django/db/ 中的一切如何工作模型/字段/related.py :)

所以,在我花几天时间研究它之前,你有没有在任何地方偶然发现类似的东西,或者你自己已经写过类似的东西?

4

2 回答 2

1

嗯……为什么?和..不要!所有流行的 sql 数据库都可以很好地扩展。你不应该害怕内部连接!.. 他们没问题!

您尝试做的事情有点痛苦......抛开这一点,如果您删除了 AnotherModel 实例,您会怎么做?扫描所有 MyModel 表以获取字符串 ID?当 Django 5.6.6.1 出现并且不兼容时会发生什么?改写?还要考虑那里的管理模块和影响/更改!

不要从一开始就过度使用最微小的性能!修复是否损坏,测试是否损坏!

在应用程序的架构上投入更多时间,你会没事的!

回答你的问题:没有,我也想过这样的事情,搜索一下,但没有发现任何有用的东西!

于 2011-07-28T17:24:56.673 回答
0

你将无法以你想要的方式逆转。相反,您只需向 AnotherModel 添加一个属性函数:

class AnotherModel(models.Model):
    // set up model here

    def mymodels(self):
        return MyModel.objects.filter(anotherlist__contains=self.pk)

那应该行得通。

于 2011-10-19T18:04:41.090 回答