一、需求:
Django實現自定義文件名存儲文件
使文件名看起來統一
避免收到中文文件導致傳輸、存儲等問題
相同的文件也需要使用不同的文件名
二、實現思路:
思路:
生成14位隨機字母加數字、后10位采用時間戳。從而實現相同文件不同文件名
1.view版:
在view接收到文件名之后進行重命名,不修改Django默認的文件存儲邏輯。從而實現需求
2.upload_to版
參考鏈接:https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.FileField.upload_to
官方原文:
upload_to may also be a callable, such as a function. This will be called to obtain the upload path, including the filename.
upload_to也可以是可調用的,例如函數。這將被調用以獲得上載路徑,包括文件名。
3.自定義存儲系統:
暫時沒那個必要:只是單純的修改個文件名而已
4.forms版(20210206補充):
使用clean方法對文件格式驗證並修改文件名
三、具體實現:
-
views版:
涉及views.py 、utils.py(自定義)
-
views.py:
class UploadIdentImageView(APIView): def get(self, request, *args, **kwargs): return Response({"msg":"ident", "status_code": True}) def post(self, request, *args, **kwargs): # from somewhere import handle_uploaded_file file_name = request.FILES.get("file", None) if not file_name: return Response({"msg": "ident", "status_code": False}) from test_app.utils import custom_file_name file_name.name = custom_file_name(file_name) models_object = models.IdCardImage(image_path=file_name) models_object.save() print(models_object) return Response({"msg":"ident", "status_code": True})
-
test_app\utils.py
def random_str(): import random import time num_set = [chr(i) for i in range(48, 58)] char_set = [chr(i) for i in range(97, 123)] total_set = num_set + char_set bits = 14 value_set = "".join(random.sample(total_set, bits)) return value_set + str(int(time.time())) def custom_file_name(file_name): file_type = str(file_name).split(".")[-1] new_file_name = random_str().upper() return ".".join([new_file_name,file_type])
-
-
upload_to版:
涉及models.py。test_app\utils.py沿用上面內容
-
models.py
def user_directory_path(upload_to): def wrapper(instance, filename): import datetime import os from mini_programe.utils import custom_file_name filename = custom_file_name(filename) dirname = datetime.datetime.now().strftime(upload_to) new_upload_to = os.path.join(dirname,filename) return new_upload_to return wrapper class IdCardImage(models.Model): f_id = models.ForeignKey(Users, on_delete=models.SET_NULL,null=True,verbose_name="用戶",related_name="user_id_card_img") # image_path = models.FileField(upload_to='media/id_card_img/%Y/%m/') image_path = models.FileField(upload_to=user_directory_path('media/id_card_img/%Y/%m/'))
-
4.forms版
- forms.py
class IdCardImageForm(forms.ModelForm):
class Meta:
model = models.IdCardImage
fields = "__all__"
def clean_image_path(self): #clean_字段名
file = self.cleaned_data["image_path"]
ext = file.name.split(".")[-1].lower()
if ext != "png":
raise forms.ValidationError("僅允許上傳png文件")
new_file_name = random.randint(111111111,9999999999)
file.name = "%d.png"%new_file_name
return file
- models.py
class IdCardImage(models.Model):
f_id = models.ForeignKey(Users, on_delete=models.SET_NULL,null=True,verbose_name="用戶",related_name="user_id_card_img")
image_path = models.FileField(upload_to='media/id_card_img/%Y/%m/')
- views.py
class UploadIdentImageView(TemplateView):
def get(self,....)
....
def post(self,request,*args,**kwargs):
check_form = forms.IdCardImageForm(request.POST,request.FILES)
if not check_form.is_valid():
return JsonResponse({'message': check_form.errors, "code": 400})
instance = check_form.save()
return JsonResponse({'message': instance.name + ",保存成功","code":200})
- upload.html
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function upload_pdf() {
const csrftoken = getCookie('csrftoken');
var form = new FormData();
form.append("f_id", $("#f_id").val());
form.append("image_path", $("#image_path")[0].files[0]);
$.ajax({
headers: {'X-CSRFToken': csrftoken},
url: "{% url 'add_data' %}",
type: "POST",
data: form,
processData: false,
contentType: false,
cache: false,
success: function (result) {
if (result.code === 200) {
alert_message(JSON.stringify(result.message));
} else {
console.log("success", result);
alert_message(JSON.stringify(result.message));
}
},
fail: function (result) {
console.log("fail",);
alert_message(result.info);
},
error: function (result) {
alert_message(result.status + ": " + result.statusText);
}
});
}
四、最終效果:
- 圖片:
五、效果對比:
個人更傾向於方案二或方案四,理由是:views.py文件中的處理函數的處理邏輯應該看起來簡單一些。例如采用方案二整理后的view.py看起來像這樣:
class UploadIdentImageView(APIView):
def get(self, request, *args, **kwargs):
return Response({"msg":"ident", "status_code": True})
def post(self, request, *args, **kwargs):
file_name = request.FILES.get("file", None)
if not file_name:
return Response({"msg": "ident", "status_code": False})
models_object = models.IdCardImage(image_path=file_name)
models_object.save()
return Response({"msg":"ident", "status_code": True})
生成隨機字母加數字的邏輯參考鏈接:https://blog.csdn.net/u010039418/article/details/86013620