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

时间:2017-10-29 11:36:39

标签: python django django-orm

我正在使用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的使用),我想利用自然键而无需对自然键进行硬编码(或者#34;识别每个模型的"字段)。目前,我"识别"一个对象由它的独特字段 - 我做:

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

但是Django似乎正在选择它"识别"字段不同。

1 个答案:

答案 0 :(得分:0)

我想我已经发现了。 Django不仅会调用get_by_natural_key,而是首先调用natural_key。如果它没有模型的实例,它是如何做到的?

它只是从构造函数创建一个没有数据库支持的实例(d'哦!):Model(**data)。请参阅build_instance中的django.core.serializers.base。然后它在新创建的对象上调用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