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

Python Django loaddata如何知道哪些字段构成自然键?,python,django,django-orm,Python,Django,Django Orm,我使用Django的dumpdata来保存数据,并使用loaddata来重新加载数据。我也使用自然键。我的模型与此类似: 类链接管理器(models.Manager): def get_by_natural_键(self,url): 返回self.get(url=url) 类链接(models.Model): 对象=链接管理器() title=models.CharField(最大长度=200) url=models.URLField() def自然_键(自): 返回(self.url,) 如

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

类链接管理器(models.Manager):
def get_by_natural_键(self,url):
返回self.get(url=url)
类链接(models.Model):
对象=链接管理器()
title=models.CharField(最大长度=200)
url=models.URLField()
def自然_键(自):
返回(self.url,)
如果我导出并重新导入数据,Django会识别出对象已经存在,并且不会创建重复项。如果我更改标题,它将正确更新对象。但是,如果我更改URL,它会正确地将其视为新对象-尽管我忘记标记
URL
unique!它怎么猜出我的意图

django如何知道我的
url
字段是自然键?没有
get\u natural\u字段
函数。Django可以调用类上的
natural\u 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\u by\u natural\u key
,它首先调用
natural\u key
。如果没有模型的实例,它是如何做到的

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

build\u实例
函数的来源(Django 1.11.2):


我想我已经发现了。Django不只是调用
get\u by\u natural\u key
,它首先调用
natural\u key
。如果没有模型的实例,它是如何做到的

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

build\u实例
函数的来源(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