2013-05-26 2 views
0

У меня есть следующие модели:
Джанго объект нагрузки в случае, если уникальный ключ Дубликат

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

Всякий раз, когда я получаю список Car из файла XML, некоторые из них обнаружиться несколько раз
(с тем же слизняком), если я пытаюсь спасти, я получаю
IntegrityError(1062, "Duplicate entry 'car-slug' for key 'slug'")

Я хочу, чтобы загрузить существующий автомобиль (или обновлял его, в зависимости от того легче) в случае, если есть Дублированная ошибка.
Но я хочу, чтобы он был достаточно общим, чтобы он работал для model_slug (или любого уникального поля, которое генерирует эту ошибку).

+0

Я закончил тем, что писал https://gist.github.com/kidsil/5658666 – Asaf

ответ

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 объекта присвоить его так, чтобы сохранить() команда выглядит следующим образом:

the_id = generic_object.save() #e.g. Car 
if the_id: 
    generic_object.id = the_id 
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 
+0

к сожалению, это решение не является достаточно общим для меня, так как пуля может быть различной, но model_slug то же самое , и в этом случае он все равно будет вызывать IntegrityError. Я стараюсь быть как можно более конкретным (без полей) – Asaf

+0

Просто добавьте и измените фильтры напрямую? Единственный другой способ - это обернуть все в try/except - что действительно глупо. Итак, что вы делаете, вы завершаете XML-логику вокруг этого фрагмента.Всякий раз, когда вы читаете запись из файла XML, проверяйте, существует ли объект с «slug» или «model-slug» - вытащите его, если он существует, или создайте новый, если он этого не делает (это то, что ' get_or_create' будет делать); и, таким образом, вы избежите ошибок целостности. Вы также можете splat (используя '** dict'), а затем искать в поле _every_ в модели. –

0

вы можете фильтровать записи дубликатов автомобиля в памяти, а затем вызывать создание новых элементов, например, ,

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 на уникальных полях, а затем сохранить другие attribues с моделью сохранения, например,

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() 
Смежные вопросы