Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django加载对象,以防唯一键重复_Python_Django_Django Models - Fatal编程技术网

Python Django加载对象,以防唯一键重复

Python Django加载对象,以防唯一键重复,python,django,django-models,Python,Django,Django Models,我有以下型号: class Car(models.Model): id = models.AutoField(primary_key=True) slug = models.CharField(max_length=128L, unique=True, blank=True) name = models.CharField(max_length=128L, blank=True) model_slug = models.CharField(max_length=128L, unique=

我有以下型号:

class Car(models.Model):
 id = models.AutoField(primary_key=True)
 slug = models.CharField(max_length=128L, unique=True, blank=True)
 name = models.CharField(max_length=128L, blank=True)
 model_slug = models.CharField(max_length=128L, unique=True, blank=True)
 ...
每当我从XML文件中获取
Car
列表时,其中一些会多次出现
(使用相同的slug),如果我试图保存它,我会得到IntegrityError(1062,“钥匙“slug”的重复输入“car slug”)

我希望它加载现有的汽车(或更新,以较容易的为准),以防出现重复错误
但我希望它具有足够的通用性,以便适用于model_slug(或任何生成该错误的唯一字段)。

您需要:

无论您为
get\u或\u create
提供什么参数,它都将使用这些参数来搜索模型的现有记录


假设您不知道哪些字段组合将触发重复。最简单的方法是找出模型中哪些字段具有该限制(即
unique=True
)。您可以从模型中反思这些信息,或者更简单的方法是将这些字段传递到
get\u或\u create

第一步是在XML字段和模型字段之间创建映射:

xml_lookup = {}
xml_lookup = {'CAR-SLUG': 'slug'}  # etc. etc.
如果需要,您可以填充所有字段,但我的建议是只填充那些对其具有唯一约束的字段

接下来,在解析XML时,为每个记录填充一个字典,映射每个字段:

for row in xml_file:
    lookup_dict = {}
    lookup_dict[xml_lookup[row['tag']] = row['value']  # Or something similar
    car, created = Car.objects.get_or_create(**lookup_dict)
    if created:
       # Nothing matched, a new record was created
       # Any any logic you need here
    else:
       # Existing record matched the search parameters
       # Change/update whatever field to prevent the IntegrityError
       car.model_slug = row['MODEL_SLUG']
       # Set/update fields as required
    car.save()  # Save the modified object

您可以先在内存中过滤重复的汽车条目,然后在新条目上调用create,例如

uniq_attrs = ['slug', 'model_slug', ...]
existed_attrs = set()
for car in car_list:
    # skip the duplicates
    if any([(attr, car[attr]) in existed_attrs for attr in uniq_attrs):
        continue
    uniq_attrs.update([(attr, car[attr]) for attr in uniq_attrs])

    # save the new car to db
    Car.objects.save(....)
或者您可以尝试在唯一字段上获取或创建属性,然后使用模型保存保存其他属性,例如

for car in car_list:
    attr_dict = {attr:car[attr] for attr in uniq_attrs}
    car, created = Car.objects.get_or_create(**attr_dict)

    # already created before
    if created:
        continue

    # save other attributes
    car.set(...)
    car.set(...)
    car.save()

最后,我在模型上编写了一个自定义保存(这样我的代码就不会更改,只更改模型):

现在,我返回对象的ID以分配它,因此save()命令如下所示:

the_id = generic_object.save() #e.g. Car
if the_id:
    generic_object.id = the_id

遗憾的是,这个解决方案对我来说不够通用,因为slug可能不同,但是model_slug是相同的,在这种情况下,它仍然会引发IntegrityError。我尽量不具体(没有字段名),直接添加和修改过滤器?唯一的另一种方法是你把所有的东西都用try/except来包装,这真是愚蠢。所以,您要做的是将XML逻辑包装在这个代码段周围。无论何时从XML文件中读取记录,都要检查对象是否存在
slug
,或者
model slug
——如果存在,请重新获取,如果不存在,请创建一个新的(这就是
get\u或\u create
的作用);这样就可以避免完整性错误。你也可以用splat(通过使用
**dict
)然后搜索模型中的每个字段
def save(self, *args, **kwargs):
    try:
        super(Car, self).save(*args, **kwargs)
    except IntegrityError, e:
        existing_object = Car.objects.get(slug=self.slug)
        self = existing_object
        super(Car, self).save(*args, **kwargs)
        return existing_object.id
the_id = generic_object.save() #e.g. Car
if the_id:
    generic_object.id = the_id