Load File From URL Widget

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import os, urllib, urllib2, mimetypes
from urlparse import urlparse

from django.forms.widgets import FileInput, CheckboxInput, TextInput

from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

from django.core.files import File
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.files.temp import NamedTemporaryFile

from django.utils.html import escape, conditional_escape
from django.utils.translation import ugettext, ugettext_lazy
from django.utils.encoding import StrAndUnicode, force_unicode
from django.utils.safestring import mark_safe

FILE_INPUT_CONTRADICTION = object()

class URLFileInput(FileInput):
    initial_text = ugettext_lazy('Currently')
    input_text = ugettext_lazy('Change')
    clear_checkbox_label = ugettext_lazy('Clear')
    url_text_label = ugettext_lazy('From URL')

    template_with_initial = u'<p class="file-upload">%(initial_text)s: %(initial)s %(clear_template)s<br />%(url_template)s<br />%(input_text)s: %(input)s</p>'
    template_only_url = u'<p class="file-upload">%(url_template)s<br />%(input_text)s: %(input)s</p>'
    
    template_with_clear = u'<span class="clearable-file-input">%(clear)s <label for="%(clear_checkbox_id)s">%(clear_checkbox_label)s</label></span>'
    template_with_url = u'%(url_text_label)s: %(url)s'

    def clear_checkbox_name(self, name):
        """
        Given the name of the file input, return the name of the clear checkbox
        input.
        """
        return name + '-clear'

    def clear_checkbox_id(self, name):
        """
        Given the name of the clear checkbox input, return the HTML id for it.
        """
        return name + '_id'

    def url_text_name(self, name):
        """
        Given the name of the file input, return the name of the url text
        input.
        """
        return name + '-url-clear'

    def url_text_id(self, name):
        """
        Given the name of the url text input, return the HTML id for it.
        """
        return name + '_url_id'

    def render(self, name, value, attrs=None):
        substitutions = {
            'initial_text': self.initial_text,
            'input_text': self.input_text,
            'clear_template': '',
            'clear_checkbox_label': self.clear_checkbox_label,
            'url_text_label': self.url_text_label,
        }
        
        template = self.template_only_url
        substitutions['input'] = super(URLFileInput, self).render(name, value, attrs)

        if value and hasattr(value, "url"):
            template = self.template_with_initial
            substitutions['initial'] = (u'<a href="%s">%s</a>'
                                        % (escape(value.url),
                                           escape(force_unicode(value))))
            if not self.is_required:
                checkbox_name = self.clear_checkbox_name(name)
                checkbox_id = self.clear_checkbox_id(checkbox_name)
                substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name)
                substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id)
                substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id})
                substitutions['clear_template'] = self.template_with_clear % substitutions
        
        text_name = self.url_text_name(name)
        text_id = self.url_text_id(text_name)
        substitutions['url_text_name'] = conditional_escape(text_name)
        substitutions['url_text_id'] = conditional_escape(text_id)
        substitutions['url'] = TextInput().render(text_name, "", attrs={'id': text_id, "style":"width:400px"})
        substitutions['url_template'] = self.template_with_url % substitutions

        return mark_safe(template % substitutions)

    def value_from_datadict(self, data, files, name):
        upload = super(URLFileInput, self).value_from_datadict(data, files, name)
        if not self.is_required and CheckboxInput().value_from_datadict(
            data, files, self.clear_checkbox_name(name)):
            if upload:
                # If the user contradicts themselves (uploads a new file AND
                # checks the "clear" checkbox), we return a unique marker
                # object that FileField will turn into a ValidationError.
                return FILE_INPUT_CONTRADICTION
            # False signals to clear any existing value, as opposed to just None
            return False
        
        url = TextInput().value_from_datadict(data, files, 
                self.url_text_name(name))
        if url:
            validate = URLValidator(verify_exists=False)
            try:
                validate(url)
            except ValidationError, e:
                url = None
            
            parsed_url = urlparse(url)
            name = os.path.basename(parsed_url[2])
            ext = os.path.splitext(parsed_url[2])[1]
            
            if url and ext in [".png", ".gif", ".jpg"]:
                opener = urllib2.build_opener()
                opener.addheaders = [('User-agent', 'Mozilla/5.0')]
                ze_file = opener.open(url).read()
                upload = SimpleUploadedFile(name=name, content=ze_file, content_type=mimetypes.guess_type(name))
        
        return upload

More like this

  1. Admin Image Widget by baumer1122 5 years, 8 months ago
  2. ImageField for admin with thumbnail by semente 4 years, 10 months ago
  3. Image Widget (for admin) by moskrc 1 year, 9 months ago
  4. URL models by diverman 4 years, 6 months ago
  5. Automatically create urls for templates in a directory by blackrobot 2 years, 5 months ago

Comments

ldd (on March 26, 2013):

Thanks. This is really useful, however the description mentions a default_exts argument which does not appear to be used anywhere. Conversely, the extensions accepted are hardcoded:

if url and ext in [".png", ".gif", ".jpg"]:

#

(Forgotten your password?)