current position:Home>Django admin custom field stores links in the database after uploading files to the cloud

Django admin custom field stores links in the database after uploading files to the cloud

2022-02-01 16:22:56 stonepy

Django admin Customize Field Upload files to the cloud Store links

brief introduction

At work, I met the need to quickly build a prototype ,Django There are perfect solutions for background data management .

admin Backstage right models.FileField The solution of uploading files is to store the original data directly in the database , It is inconvenient for database size and migration , More solutions are through oss Solve storage problems ,cdn Speed up access . So you need to models.FileField To transform , Make it automatically uploaded to oss And store url Address . After searching the network, there is only one solution to this , But incomplete. ( If there are other plans, please let us know in the comment area )

Usage environment :python 3.8.8 django 3.2.5

Implementation steps

notes : I use Tencent cloud oss, So the following examples take Tencent cloud as an example , Other cloud oss Just replace the position marked by me

0、 Upload part of the file code ( Use of private information 000000 Express , Replace... By yourself )

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'  #  Replace with the user's  Region
        self.scheme = 'https'  #  Specify the use of  http/https  Protocol to access  COS, The default is  https, Not required 
        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

 Copy code 

1、 Customize Widget

Inherited forms.FileInput, Receive the page input file

# -*-*-*-*-*- encoding: utf-8 -*-*-*-*-
# @File : TencentWidget.py
# @Author : stonepy
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
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:  Unique identification list , except 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)  # type:InMemoryUploadedFile
        if not file:
            return
        file_data = b''.join(chunk for chunk in file.chunks())  #  Take out the binary data 
        upload_cloud = UploadToTencent()
        url = upload_cloud.upload_to_tencentcloud(file_data, file.name)  #  How to replace this location when replacing other clouds , Method returns to url character string 
        return url

    def render(self, name, value, attrs=None, renderer=None):  #  Template rendering part 
        context = self.get_context(name, value, attrs)
        template = loader.get_template(self.template_name).render(context)
        return mark_safe(template)

 Copy code 

2、 Customize Field

Inherited models.URLField, Used to implement URL To deal with

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)

 Copy code 

3、 Customize template

Here is the self exploration part , If you have any questions, please point out When not using custom templates , An error will be reported when entering, and the template cannot be found After browsing the source file, I found that /lib/python3.8/site-packages/django/forms/templates/django/forms/widgets/file.html, It is speculated that the corresponding position cannot be read file.html So customize a template html, The code is as follows :( Direct copy file.html Part of , Get rid of some unrecognized problems )

<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 %}>`
` Uploaded file :{% if widget.value != None %}<a href="{{ widget.value }}">{{ widget.value }}</a>{% endif %}
 Copy code 

The last one is to add support for the display of uploaded files , I don't know what the previous problem is. It can't be displayed , If you don't need it, you can delete it directly

4、 Use customization field

from customField.TencentField import TencentField
file_url = TencentField(max_length=255, default='', verbose_name=' File address ', blank=True)

 Copy code 

5、 other

5.1 The code structure

5.2 Use effect

Page shows The database stores information

Refer to the article address :www.jianshu.com/p/0522aaae3…

copyright notice
author[stonepy],Please bring the original link to reprint, thank you.
https://en.pythonmana.com/2022/02/202202011622542480.html

Random recommended