ali Saen
ali Saen

Reputation: 341

Django import export - How to skip the new rows, and only update the existed ones

When importing a file I want to skip all of the new rows that doesn't exist, and only update and change the ones that already exists, I've been trying for days to solve this problem, any ideas will help.

https://ibb.co/1Gw4Q19

also the file type is ".xls" or ".xlsx"

here's my code:

models.py:

class Author(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Category(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Book(models.Model):
    name = models.CharField('Book name', max_length=100)
    author = models.ForeignKey(Author, blank=True, null=True, on_delete=models.CASCADE)
    author_email = models.EmailField('Author email', max_length=75, blank=True)
    imported = models.BooleanField(default=False)
    published = models.DateField('Published', blank=True, null=True)
    price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    categories = models.ManyToManyField(Category, blank=True)

    def __str__(self):
        return self.name

admin.py:

class BookResource(resources.ModelResource):

    class Meta:
        model = Book
        import_id_field = 'id'
        import_id_fields = ('id',)
        fields = ('id', 'name', 'price',)
        skip_unchanged = True
        report_skipped = True
        dry_run = True


class CustomBookAdmin(ImportMixin, admin.ModelAdmin):
    resource_class = BookResource

    # tried to override it like so but it didn't work
    def skip_row(self, instance, original):
        original_id_value = getattr(original, self._meta.import_id_field)
        instance_id_value = getattr(instance, self._meta.import_id_field)
        if original_id_value != instance_id_value:
            return True
        if not self._meta.skip_unchanged:
            return False
        for field in self.get_fields():
            try:
                if list(field.get_value(instance).all()) != list(field.get_value(original).all()):
                    return False
            except AttributeError:
                if field.get_value(instance) != field.get_value(original):
                    return False
        return True

Upvotes: 1

Views: 2966

Answers (3)

Sammrafi
Sammrafi

Reputation: 537

here is the updated version

def skip_row(self, instance, original, row, import_validation_errors=None):
    return getattr(original, "pk") is None

Upvotes: 0

Rami Alloush
Rami Alloush

Reputation: 2636

The full solution exists here

To only update existing items while ignoring any new item you can use:

# Do not import any new items. Only update records
def skip_row(self, instance, original):
    if original.id:
        return False
    return super(BookResource, self).skip_row(instance, original)

To import only new items while preventing updates you can use:

# Only import new items. Do not update any record
def skip_row(self, instance, original):
    if not original.id:
        return False
    return True

This assumes import_id_fields = ('id',) and resource is called BookResource

Upvotes: 1

Matthew Hegarty
Matthew Hegarty

Reputation: 4306

So if you want to skip any rows in the import file which do not already exist in the database, then you can ignore any rows which don't have a pk (i.e. have not previously been persisted):

Just add the following to your BookResource sub class

def skip_row(self, instance, original):
    return getattr(original, "pk") is None

I hope this works - let me know if I've misunderstood anything.

Upvotes: 1

Related Questions