Django : customizing FileField value while editing a model

前端 未结 4 1273
孤城傲影
孤城傲影 2021-02-04 13:27

I\'ve got a model, with FileField. When I edit this model in a view, I want to change the \"current\" value of FileField which gets displayed in the vi

相关标签:
4条回答
  • 2021-02-04 13:37

    Django 1.10.x or older version


    The easiest way is to override the template_substitution_values in default ClearableFileInput django widget that will be used later in rendering the form. This is a much cleaner approach that does not result in any unnecessary code duplication.

    from os import path
    from django.forms.widgets import ClearableFileInput
    from django.utils.html import conditional_escape
    
    class CustomClearableFileInput(ClearableFileInput):
        def get_template_substitution_values(self, value):
            """
            Return value-related substitutions.
            """
            return {
                'initial': conditional_escape(path.basename(value.name)),
                'initial_url': conditional_escape(value.url),
            }
    

    then use the widget in forms.py as follow:

    class DemoVar_addform(ModelForm):
        Welcome_sound = forms.FileField(widget=CustomClearableFileInput)    
        ...
    
        class Meta:
            model = DemoVar_model
    
        ...
    

    Django 1.11.x or later versions


    Check ImageField / FileField Django form Currently unable to trim the path to filename.

    0 讨论(0)
  • 2021-02-04 13:39

    You need to override the ClearableFileInput that is currently used, to change the way it's displayed.

    Here is the code of the new ShortNameFileInput which inherit from the default ClearableFileInput with just a change on the 19th line to only show the file name:

    from django.forms.widgets import ClearableFileInput
    import os
    # missing imports
    from django.utils.safestring import mark_safe
    from cgi import escape
    from django.utils.encoding import force_unicode
    
    class ShortNameClarableFileInput(ClearableFileInput):
        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,
            }
            template = u'%(input)s'
            substitutions['input'] = super(ClearableFileInput, 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(os.path.basename(value.url))))) # I just changed this line
                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
    
            return mark_safe(template % substitutions)
    

    To use it in your form, you'll have to manually set the widget you want to use :

    class DemoVar_addform(ModelForm):
        ...
        class Meta:
            model = DemoVar_model
            widgets = {
                'Welcome_sound': ShortNameClarableFileInput,
            }                    
    

    That should do the trick.

    0 讨论(0)
  • 2021-02-04 13:43

    If you want an easier way and avoid to rewrite the render logic of the widget, you can do a little hack.

    from os import path
    from django import forms
    
    
    class FormatString(str):
    
        def format(self, *args, **kwargs):
            arguments = list(args)
            arguments[1] = path.basename(arguments[1])
            return super(FormatString, self).format(*arguments, **kwargs)
    
    
     class ClearableFileInput(forms.ClearableFileInput):
    
         url_markup_template = FormatString('<a href="{0}">{1}</a>')
    

    And then manually set the widget for the field.

    class DemoVar_addform(ModelForm):
    
        class Meta:
            model = DemoVar_model
            widgets = {
                'Welcome_sound': ClearableFileInput,
            }   
    
    0 讨论(0)
  • 2021-02-04 13:54

    One way of doing it, would be to write a custom form widget and override the render method.

    0 讨论(0)
提交回复
热议问题