Django channels file/image upload

后端 未结 2 466
暖寄归人
暖寄归人 2020-12-29 15:35

I would like to upload files and images using django-channels but i don\'t have any idea where to start. Seems like there is not much documentation about websockets and file

相关标签:
2条回答
  • 2020-12-29 15:56

    The only real way to do this is with Channels 2 because the consumers persist for the duration of the session and you can put a file object on it as an instance variable.

    You can see how I use the file field and first send some initialization parameters on it. I pulled out the important parts:

    // Some class setup before this
    
    // File field object
    this.file = field.files[0];
    init_params.action = 'prepare';
    init_params.file_name = this.file.name;
    init_params.file_size = this.file.size;
    
    // This is a wrapper I have that gets a websocket. 
    // The callback is called on connect. It sends the initialization parameters.
    var ws = get_websocket(url, function(){
        this.send(JSON.stringify(init_params));
    });
    
    // After the initialization params are sent this is called with 0 as a parameter. 
    // As the web server oks each chunk this is called with the next offset to send. chunk_size needs to be set somewhere.
    var load_data = function(index) {
        var end =  index + this.chunk_size;
        if (index >= this.file.size)
            return;
        if (end > this.file.size)
            end = this.file.size;
        ws.send(this.file.slice(index, end));
    }.bind(this);
    
    ws.onmessage = function(msg) {
        var message = JSON.parse(msg.data);
        switch (message.action) {
            case 'progress':
                // This is called each time a chunk is written
                load_data(message.file_size);
                break;
            case 'ready':
                // This comes in to kick everything off
                load_data(0);
                break;
            case 'complete':
                // Handle complete
                break;
                }
            };
        }.bind(this);
    

    In the consumer we check if it is text data and if it is we process it as JSON to set up the file. If its binary data we write each chunk out like this.

        async def handle_json(self, message):
             self.session = {
                 # Set up file object and attributes
             }
    
        async def handle_chunk(self, message, **kwargs):
            upload_size = self.session.get('upload_size')
            temp_destination = self.session.get('upload_file')
    
            if not upload_size or not temp_destination:
                return self.error('Invalid request. Please try again.')
    
            self.session['upload_file'].write(message)
            size = self.session['upload_file'].tell()
    
            percent = round((size / upload_size) * 100)
            await self.send_json({
                'action': 'progress',
                'percent': percent,
                'file_size': size
            })
    
            if size >= upload_size:
                self.session['upload_file'].flush()
                file_name = await self.handle_complete(self.session['upload_file'])
    
                await self.send_json({
                    'action': 'complete',
                    'file_size': size,
                    'file_name': file_name
                }, close=True)
    
    0 讨论(0)
  • 2020-12-29 15:57

    I also faced the same problem and I solved it by uploading the the Image/File in S3 bucket. we just need to decode the base64 code and upload the file and return the URL to websocket. We can also provide preview of the image by providing the file type.

    def file_upload(self, data):
        # Convert decode the base64 data 
        file = base64.b64decode(data['data']['content'].split(',')[-1])
        filename = data['data']['filename']
        type = data['data']['type']
        AWS_ACCESS_KEY_ID = getattr(settings, "AWS_S3_ACCESS_KEY_ID")
        AWS_SECRET_ACCESS_KEY = getattr(settings, "AWS_S3_SECRET_ACCESS_KEY")
        bucket_name = getattr(settings, "AWS_STORAGE_BUCKET_NAME")
        conn = boto.connect_s3(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
        bucket = conn.get_bucket(bucket_name)
        k = Key(bucket)
        k.key = getattr(settings, "AWS_CHAT_DIR") + '/' + filename
        k.set_metadata('Content-Type', type)
        k.set_contents_from_string(file)
        url = 'https://' + getattr(settings, "AWS_BUCKET_URL") + '/' + k.key
        message = url
        content = {
            'command': 'new_message',
            'message': self.message_to_json(message)
        }
        return self.send_chat_message(content)
    
    0 讨论(0)
提交回复
热议问题