Django

Code

Ticket #2534: filefield_core_fixes.diff

File filefield_core_fixes.diff, 6.6 kB (added by anonymous, 4 years ago)

Patch to allow FileFields? to be used as core fields

  • django/db/models/manipulators.py

    old new  
    167167                                pass 
    168168 
    169169                    for f in related.opts.fields: 
    170                         if f.core and not isinstance(f, FileField) and f.get_manipulator_new_data(rel_new_data, rel=True) in (None, ''): 
     170                        if f.core and f.get_manipulator_new_data(rel_new_data, rel=True) in (None, ''): 
    171171                            all_cores_given = False 
    172                         elif f.core and not isinstance(f, FileField) and f.get_manipulator_new_data(rel_new_data, rel=True) not in (None, ''): 
     172                        elif f.core and f.get_manipulator_new_data(rel_new_data, rel=True) not in (None, ''): 
    173173                            all_cores_blank = False 
    174174                        # If this field isn't editable, give it the same value it had 
    175175                        # previously, according to the given ID. If the ID wasn't 
  • django/db/models/fields/__init__.py

    old new  
    532532        validators.isValidEmail(field_data, all_data) 
    533533 
    534534class FileField(Field): 
    535     def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs): 
     535    def __init__(self, verbose_name=None, name=None, upload_to='', can_delete=False, **kwargs): 
    536536        self.upload_to = upload_to 
     537        self.can_delete = can_delete 
    537538        Field.__init__(self, verbose_name, name, **kwargs) 
     539        assert (not self.can_delete) or self.null, "A FileField must have null=True if can_delete=True" 
    538540 
    539541    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): 
    540542        field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow) 
     
    572574        field_list[1].validator_list.append(isWithinMediaRoot) 
    573575        return field_list 
    574576 
     577    def get_manipulator_new_data(self, new_data, rel=False): 
     578        # Return the value which the field will take, if it is saved. 
     579        # This will be either the pathname of the uploaded file, or the 
     580        # pathname of the existing file, if no file was uploaded. 
     581        if rel: 
     582            extract = lambda field: (new_data.get("%s%s" % (self.name, field), [None])[0]) 
     583        else: 
     584            extract = lambda field: (new_data.get("%s%s" % (self.name, field), None)) 
     585        if extract('_delete'): 
     586            return None 
     587        try: 
     588            file = extract('_file') 
     589            return self.get_filename(file['filename']) 
     590        except (IndexError, KeyError, TypeError): 
     591            pass 
     592        return extract('') 
     593 
    575594    def contribute_to_class(self, cls, name): 
    576595        super(FileField, self).contribute_to_class(cls, name) 
    577596        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self)) 
     
    590609                os.remove(file_name) 
    591610 
    592611    def get_manipulator_field_objs(self): 
     612        if self.can_delete: 
     613            return [forms.FileUploadField, forms.HiddenField, forms.LabeledCheckbox] 
    593614        return [forms.FileUploadField, forms.HiddenField] 
    594615 
    595616    def get_manipulator_field_names(self, name_prefix): 
     617        if self.can_delete: 
     618            return [name_prefix + self.name + '_file', name_prefix + self.name, name_prefix + self.name + '_delete'] 
    596619        return [name_prefix + self.name + '_file', name_prefix + self.name] 
    597620 
    598621    def save_file(self, new_data, new_object, original_object, change, rel): 
    599         upload_field_name = self.get_manipulator_field_names('')[0] 
    600         if new_data.get(upload_field_name, False): 
     622        field_names = self.get_manipulator_field_names('') 
     623        upload_field_name = field_names[0] 
     624        # Delete only if delete checkbox is present and checked 
     625        if self.can_delete and ((rel and new_data.get(field_names[2], [False])[0]) or 
     626                                (not rel and new_data.get(field_names[2], False))): 
     627            file_name = getattr(original_object, 'get_%s_filename' % self.name)() 
     628            # If file exists, delete it 
     629            if file_name and os.path.exists(file_name): 
     630                os.remove(file_name) 
     631            setattr(new_object, self.name, None) 
     632            new_object.save() 
     633        elif new_data.get(upload_field_name, False): 
    601634            func = getattr(new_object, 'save_%s_file' % self.name) 
    602635            if rel: 
    603636                func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"]) 
     
    635668        FileField.__init__(self, verbose_name, name, **kwargs) 
    636669 
    637670    def get_manipulator_field_objs(self): 
     671        if self.can_delete: 
     672            return [forms.ImageUploadField, forms.HiddenField, forms.LabeledCheckbox] 
    638673        return [forms.ImageUploadField, forms.HiddenField] 
    639674 
    640675    def contribute_to_class(self, cls, name): 
  • django/forms/__init__.py

    old new  
    993993            v(field_data, all_data) 
    994994        except validators.ValidationError, e: 
    995995            raise validators.CriticalValidationError, e.messages 
     996 
     997class LabeledCheckbox(CheckboxField): 
     998    """ 
     999    A checkbox for which is_required is allowed to be set to False, and 
     1000    which optionally displays a text label before its form control. 
     1001    """ 
     1002    def __init__(self, field_name, checked_by_default=False, validator_list=None, is_required=False, label=None): 
     1003        self.label = label 
     1004        # This default is to support using this checkbox as a delete field in 
     1005        # FileField objects. It is only required because there is no easy way 
     1006        # to send unique constructor parameters to multiple manipulator field 
     1007        # objects. 
     1008        if self.label == None: 
     1009            self.label = gettext_lazy("Delete") 
     1010        super(LabeledCheckbox, self).__init__(field_name, checked_by_default, validator_list) 
     1011 
     1012    def render(self, data): 
     1013        checked_html = '' 
     1014        if data or (data is '' and self.checked_by_default): 
     1015            checked_html = ' checked="checked"' 
     1016        label_html = '' 
     1017        if self.label: 
     1018            label_html = " %s " % self.label 
     1019        return '%s<input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" />' % \ 
     1020            (label_html, self.get_id(), self.__class__.__name__, 
     1021            self.field_name, checked_html) 
     1022