Не сохранять модель на дубликате файла - Django 2 - PullRequest
1 голос
/ 29 апреля 2019

Я пытаюсь проверить существующий файл и перезаписать его, пока я могу сделать это с помощью пользовательского хранилища, которое выглядит примерно так

from django.core.files.storage import FileSystemStorage

class DuplicateFileStorage(FileSystemStorage):

    def get_available_name(self, name, max_length=None):

        return name

    def _save(self, name, content):
        if self.exists(name):
            self.delete(name)

        return super(DuplicateFileStorage, self)._save(name, content)

Приведенный выше класс проверяет существующийфайл и удаляет его.

И модель, которую он ищет:

class DataStorageModel(models.Model):

    user = models.ForeignKey(User, related_name='data_storage', on_delete=models.CASCADE)
    file_name = models.CharField(blank=True, max_length=200, help_text="File Name")
    file = models.FileField(blank=True, null=True, upload_to=user_directory_path, storage=DuplicateFileStorage())
    relative_path = models.CharField(blank=True, max_length=200, help_text="Relative Path if folder else null")

    def delete(self, using=None, keep_parents=False):

        self.file.delete()

        return super(DataStorageModel, self).delete()

Проблема в том, что, хотя он удаляет и записывает тот же файл, он также создает новую запись модели с тем жесуществующий путь, то есть, если я загружаю один и тот же файл дважды, я получаю один файл в пути ОС, но две записи модели.Примерно так (здесь есть изображение):

screenshot

Поэтому я попытался использовать метод clean() с self.file.storage.exists(self.file.name) (согласно this ) но я получаю существование как False, хотя там есть файл.

def save(self, force_insert=False, force_update=False, using=None,
         update_fields=None):

    self.full_clean()

    return super(DataStorageModel, self).save()

def clean(self):

    print(self.file.storage.exists(self.file.name))  # <--- False

Поэтому мой вопрос: как мне проверить, существует ли дублирующий файл, перезаписатьфайл, но не создать новую запись?

Редактировать

Я забыл вставить user_director_path():

def user_directory_path(instance, filename):
    """
    If relative path is not ``null`` the files will be stored as is else it will be
    stored to the root directory.
    """

    if instance.relative_path != 'null':
        return 'user_{0}{1}'.format(instance.user.id, instance.relative_path)
    return 'user_{0}/{1}'.format(instance.user.id, filename)

Я думаю,Я получил это, если я сделаю это:

def clean_fields(self, exclude=None):

    if self.file.storage.exists('user_{0}{1}'.format(self.user.id, self.relative_path)):
        raise ValidationError('File already exists.')

Это работает, но вся загрузка не удалась, даже перезапись файлов

1 Ответ

0 голосов
/ 29 апреля 2019

Условие, if instance.relative_path != 'null': неверно. Это должно быть просто if instance.relative_path:

Когда я попробовал ваш фрагмент, я почувствовал что-то не так с функцией user_directory_path. Итак, я изменил его на что-то вроде ниже.

def user_directory_path(instance, filename):
    """
    If relative path is not ``null`` the files will be stored as is else it will be
    stored to the root directory.

    The "relative_path" path should not be start or ends with a slash ("/") but, can use slash inside

    /foo/ -> Not allowed
    /foo/bar -> Not allowed
    foo/bar/ -> Not allowed

    foo -> Allowed
    foo/bar -> Allowed
    foo/bar/foobar -> Allowed

    """

    if instance.relative_path:
        relative_path = instance.relative_path
        if relative_path[0] == '/':
            relative_path = relative_path[1:]
        if relative_path[:-1] == '/':
            relative_path = relative_path[:-1]

        return 'user_{0}/{1}/{2}'.format(instance.user.id, relative_path, filename)
    return 'user_{0}/{1}'.format(instance.user.id, filename)

Теперь, перейдя к нашему решению, я создал примерное представление, которое решит проблему.

from django.http.response import HttpResponse


def foo(request):
    if request.method == 'POST':
        create_data = {
            "user_id": request.user.pk,
            "file": request.FILES['file_name']
        }

        ds_temp = DataStorageModel(**create_data)
        path = user_directory_path(ds_temp, ds_temp.file.name)
        try:
            ds_existing = DataStorageModel.objects.get(file=path)
            ds_existing.file = create_data['file']
            ds_existing.save()
            return HttpResponse("instance modified")
        except DataStorageModel.DoesNotExist:
            ds_temp.save()
            return HttpResponse("new instance created")
    return HttpResponse("HTTP GET method")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...