简体   繁体   English

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

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

I am using Django's dumpdata to save data and loaddata to reload it. 我正在使用Django的dumpdata保存数据,并使用loaddata重新加载它。 I am also using natural keys. 我也在使用自然键。 My model looks similar to this: 我的模型与此类似:

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, )

If I export and reimport the data, Django recognizes that the objects already exist and doesn't create duplicates. 如果导出并重新导入数据,则Django会识别出对象已存在,并且不会创建重复项。 If I change the title, it correctly updates the objects. 如果更改标题,它将正确更新对象。 However, if I change the URL, it correctly treats it as a new object - although I forgot to mark url unique! 但是,如果我更改了URL,它将正确地将其视为一个新对象-尽管我忘记标记url唯一! How does it guess my intent? 它如何猜出我的意图?

How does django know that my url field is the natural key? django如何知道我的url字段是自然键? There is no get_natural_fields function. 没有get_natural_fields函数。 Django could call natural_key on the class instead of an instance to get the fields, but that seems really brittle: Django可以在而不是实例上调用natural_key来获取字段,但这似乎很脆弱:

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

The reason I want to know this is that I am writing my own special importer (to replace my use of loaddata), and I would like to take advantage of natural keys without hardcoding the natural key (or the "identifying" fields) for each model. 我想知道的原因是,我正在编写自己的特殊导入器(以替换我对loaddata的使用),并且我想利用自然键,而不用为每个自然键(或“标识”字段)进行硬编码模型。 Currently, I "identify" an object by it's unique fields - I do: 目前,我通过唯一字段“标识”对象-我这样做:

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

but Django seems to be choosing it's "identifying" fields differently. 但是Django似乎选择了不同的“标识”字段。

I think I've found it out. 我想我已经发现了。 Django does not just call get_by_natural_key , it first calls natural_key . Django不仅调用get_by_natural_key ,它还首先调用natural_key How does it do that, if it doesn't have an instance of the model? 如果没有该模型的实例,该怎么做?

It simply creates an instance, not backed by the database, from the constructor (d'oh!): Model(**data) . 它只是从构造函数(d'oh!): Model(**data)创建一个实例,该实例不受数据库支持。 See build_instance in django.core.serializers.base . 请参阅django.core.serializers.base build_instance Then it calls natural_key on the newly created object, and immediately get_by_natural_key to retrive the pk that belongs to the object, if present in the database. 然后, natural_key对新创建的对象调用natural_key ,并立即get_by_natural_key检索属于该对象的pk (如果存在于数据库中)。 This way, Django does not need to know what fields the natural key depends on, it just needs to know how to get it from data. 这样,Django不需要知道自然键所依赖的字段,它只需要知道如何从数据中获取它即可。 You can just call save() on the retrieved instance, if it is in the database it will have a pk and will update, if not it will create a new row. 您可以只在检索到的实例上调用save() ,如果它在数据库中,它将有一个pk并将更新,如果没有,它将创建一个新行。

Source of the build_instance function (Django 1.11.2): 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