Python 不要在重复文件上保存模型-Django 2
我正在尝试检查一个现有文件并覆盖它,到目前为止,我可以使用一个自定义存储来做这件事,它看起来像这样Python 不要在重复文件上保存模型-Django 2,python,django,Python,Django,我正在尝试检查一个现有文件并覆盖它,到目前为止,我可以使用一个自定义存储来做这件事,它看起来像这样 from django.core.files.storage import FileSystemStorage class DuplicateFileStorage(FileSystemStorage): def get_available_name(self, name, max_length=None): return name def _save(se
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()
问题是,尽管它删除和写入了相同的文件,但它也创建了一个具有相同现有路径的新模型条目,也就是说,如果我上传两次相同的文件,我会在操作系统路径中得到一个文件,但会得到两个模型条目。类似这样(这里有一张图片):
因此,我尝试将clean()
方法与self.file.storage.exists(self.file.name)
(根据)结合使用,但得到的存在形式为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
如果我这样做,我想我得到了:
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.')
它可以工作,但整个上传都失败了,甚至没有重写文件的条件,
if instance.relative_path!='空“:
错误。如果instance.relative路径为:当我尝试你的代码片段时,我觉得
user\u directory\u 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")
如果instance.relative\u path!='空“:错误。如果instance.relative路径为:
当我尝试你的代码片段时,我觉得
user\u directory\u 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")
你试过了吗??]我应该在哪里使用它?在
clean
或save()
中,如果我在另存为DataStorageModel.objects.update_或_create(user=self.user,file=self.file)
中使用它,我会得到RecursionError:调用Python对象时超过最大递归深度
如果我使用self.objects.update_或_create(user=self.user,file=self.file)
I get manager无法联系到。您应该提供默认值
tooodid您可以尝试吗???]我应该在哪里使用它?在clean
或save()
中,如果我在另存为DataStorageModel.objects.update_或_create(user=self.user,file=self.file)
中使用它,我会得到RecursionError:调用Python对象时超过最大递归深度
如果我使用self.objects.update_或_create(user=self.user,file=self.file)
无法联系到我的get manager。您应该提供默认值
Tootrue,我忘记了这应该在视图中而不是模型中完成user\u directory\u path
您编写的内容为每个文件创建一个文件夹,即-temp.txt
它创建temp.txt/temp.txt
我的逻辑是,如果存在相对路径,它将在用户目录下创建子目录。如果相对路径不存在,则文件将保存到用户目录中。如果我正在上载文件夹,我将分别获得相对路径something/something text.txt
和文件名,(我正在使用uppy.js)上载文件夹?(文件夹还是文件?)user\u directory\u path
您编写的内容为每个文件创建一个文件夹,即-temp.txt
它创建temp.txt/temp.txt
我的逻辑是,如果存在相对路径,它将在用户目录下创建子目录。如果相对路径不存在,则文件将保存到用户目录中。如果我正在上载文件夹,我将分别获得相对路径something/something text.txt
和文件名,(我正在使用uppy.js)上载文件夹?(文件夹还是文件?)。