在工作碰到了需要快速搭建原型的事情,Django在后台数据管理这方面有完善的解决方案。
admin后台对
models.FileField
的上传文件解决方式是直接在数据库中储存原始数据,对于数据库大小和迁移等都很不便,更多的解决方案是通过oss解决储存问题,cdn访问的方式提高速度。
所以需要对
models.FileField
进行改造,使其自动上传到oss中并储存url地址。
找遍了网络只有一个对此的解决方案,但不完整(有其他方案的话在评论区告知一下)
使用环境:python 3.8.8 django 3.2.5
注:我使用的是腾讯云的oss,所以下面例子都以腾讯云为例,其他云端oss对应替换我标注的位置就可以
0、上传文件部分代码(隐私信息使用000000表示,自行替换)
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
from urllib.parse import quote
from config.config import TENCENTCloud_secret_id, TENCENTCloud_secret_key
class UploadToTencent(object):
def __init__(self):
self.region = 'ap-beijing'
self.scheme = 'https'
self.config = CosConfig(Region=self.region,
SecretId=TENCENTCloud_secret_id,
SecretKey=TENCENTCloud_secret_key,
Scheme=self.scheme)
def upload_to_tencentcloud(self, body='', key='', bucket='000000', default_dir=True):
tencent_client = CosS3Client(self.config)
if "000000" not in key and default_dir:
key = "000000" + key
if '/' in key:
filename = key.split('/')[-1]
file_dir = '/'.join(key.split('/')[:-1])+'/'
else:
filename = key
file_dir = ''
response = tencent_client.put_object(
Bucket=bucket,
Body=body,
Key=key,
EnableMD5=False
save_filename = quote(filename, 'utf-8')
print(file_dir, save_filename)
end_url = "https://download.000000.com/%s%s" % (file_dir, save_filename)
return end_url
1、自定义Widget
继承了forms.FileInput
,对页面输入文件进行接收
from django import forms
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.template import loader
from django.utils.safestring import mark_safe
from utils.tencentUploadFile import UploadToTencent
class TencentWidgets(forms.FileInput):
template_name = 'tencent_input.html'
def __init__(self, attrs=None, unique_list=None):
:param attrs:
:param unique_list: 唯一标识列表,除了id
super(TencentWidgets, self).__init__(attrs)
self.unique = unique_list
def format_value(self, value):
return value
def value_from_datadict(self, data, files, name):
file = files.get(name)
if not file:
return
file_data = b''.join(chunk for chunk in file.chunks())
upload_cloud = UploadToTencent()
url = upload_cloud.upload_to_tencentcloud(file_data, file.name)
return url
def render(self, name, value, attrs=None, renderer=None):
context = self.get_context(name, value, attrs)
template = loader.get_template(self.template_name).render(context)
return mark_safe(template)
2、自定义Field
继承了models.URLField
,用来实现URL的处理
from django import forms
from django.db import models
from customField.TencentWidget import TencentWidgets
class TencentField(models.URLField):
def __init__(self, *args, **kwargs):
self.app = kwargs.pop('app', '')
self.table = kwargs.pop('table', '')
self.unique_list = kwargs.pop('unique_list', '')
super(TencentField, self).__init__(*args, **kwargs)
def formfield(self, **kwargs):
defaults = {
'form_class': TencentFormField,
'unique_list': self.unique_list
defaults.update(kwargs)
return super(TencentField, self).formfield(**defaults)
class TencentFormField(forms.fields.URLField):
def __init__(self, unique_list=None, **kwargs):
kwargs.update({'widget': TencentWidgets(unique_list=unique_list)})
super(TencentFormField, self).__init__(**kwargs)
3、自定义template
此处为自我摸索部分,有疑问请指出
在不使用自定义模板时,进入会报错找不到模板
翻阅源文件后发现在/lib/python3.8/site-packages/django/forms/templates/django/forms/widgets/file.html
,推测是读不到对应位置的file.html
于是自定义一个模板html,代码如下:(直接复制file.html的部分,处理掉一些不识别的问题)
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value }}"{% endif %}{% for name, value in widget.attrs.items %}{% if value is not False %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %}>`
`已上传文件:{% if widget.value != None %}<a href="{{ widget.value }}">{{ widget.value }}</a>{% endif %}
最后一行为个人增加对已上传的文件显示支持,不知道之前的是什么问题无法进行显示,不需要的话可直接删除
4、使用自定义field
from customField.TencentField import TencentField
file_url = TencentField(max_length=255, default='', verbose_name='文件地址', blank=True)
5.1 代码结构
5.2 使用效果
数据库储存信息
参考文章地址:www.jianshu.com/p/0522aaae3…