繁体   English   中英

Django loaddata如何知道哪些字段构成了自然键?

[英]How does Django loaddata know which fields make the natural key?

我正在使用Django的dumpdata保存数据,并使用loaddata重新加载它。 我也在使用自然键。 我的模型与此类似:

class LinkManager(models.Manager):
    def get_by_natural_key(self, url):
        return self.get(url=url)

class Link(models.Model):
    objects = LinkManager()
    title = models.CharField(max_length=200)
    url = models.URLField()

    def natural_key(self):
        return (self.url, )

如果导出并重新导入数据,则Django会识别出对象已存在,并且不会创建重复项。 如果更改标题,它将正确更新对象。 但是,如果我更改了URL,它将正确地将其视为一个新对象-尽管我忘记标记url唯一! 它如何猜出我的意图?

django如何知道我的url字段是自然键? 没有get_natural_fields函数。 Django可以在而不是实例上调用natural_key来获取字段,但这似乎很脆弱:

>>> [f.field_name for f in Link.natural_key(Link)]
['url']

我想知道的原因是,我正在编写自己的特殊导入器(以替换我对loaddata的使用),并且我想利用自然键,而不用为每个自然键(或“标识”字段)进行硬编码模型。 目前,我通过唯一字段“标识”对象-我这样做:

obj, created = Model.objects.update_or_create(**identifying, defaults=other)

但是Django似乎选择了不同的“标识”字段。

我想我已经发现了。 Django不仅调用get_by_natural_key ,它还首先调用natural_key 如果没有该模型的实例,该怎么做?

它只是从构造函数(d'oh!): Model(**data)创建一个实例,该实例不受数据库支持。 请参阅django.core.serializers.base build_instance 然后, natural_key对新创建的对象调用natural_key ,并立即get_by_natural_key检索属于该对象的pk (如果存在于数据库中)。 这样,Django不需要知道自然键所依赖的字段,它只需要知道如何从数据中获取它即可。 您可以只在检索到的实例上调用save() ,如果它在数据库中,它将有一个pk并将更新,如果没有,它将创建一个新行。

build_instance函数的源代码(Django 1.11.2):

def build_instance(Model, data, db):
    """
    Build a model instance.

    If the model instance doesn't have a primary key and the model supports
    natural keys, try to retrieve it from the database.
    """
    obj = Model(**data)
    if (obj.pk is None and hasattr(Model, 'natural_key') and
            hasattr(Model._default_manager, 'get_by_natural_key')):
        natural_key = obj.natural_key()
        try:
            obj.pk = Model._default_manager.db_manager(db).get_by_natural_key(*natural_key).pk
        except Model.DoesNotExist:
            pass
    return obj

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM