我有以下型号:
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, "Duplicate entry 'car-slug' for key 'slug'")
我希望它加载现有的Car(或更新它,以更容易的方式),以防出现重复错误。
但我希望它足够通用,以便它适用于model_slug(或任何产生该错误的唯一字段)。
答案 0 :(得分:1)
您需要get_or_create
:
car,created = Car.objects.get_or_create(slug='car-slug')
if created:
print 'New car was created'
car.slug = 'new-car-slug'
else:
# do whatever needs to be done here
# with the existing car object, which will
# be car
# car.name = 'new name'
car.save()
无论您向get_or_create
提供什么参数,它都会使用这些参数来搜索模型的现有记录。
假设您不知道哪个字段组合会触发重复。简单的方法是找出模型中哪些字段具有该限制(即unique=True
)。您可以从模型中反省这些信息,或者更简单的方法是将这些字段简单地传递给get_or_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
答案 1 :(得分:0)
您可以先在内存中过滤重复的汽车条目,然后在新项目上调用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(....)
或者您可以在唯一字段上尝试get_or_create,然后使用模型保存保存其他属性,例如,
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()
答案 2 :(得分:0)
我最终在模型上编写了一个自定义保存(这样我的代码不会改变,只是模型):
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
现在我返回对象的ID来分配它,所以save()命令如下所示:
the_id = generic_object.save() #e.g. Car
if the_id:
generic_object.id = the_id