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