#18515: Problematic validation code in FileField
-------------------------------+-------------------------------------------
     Reporter:  yoyoma         |      Owner:  nobody
         Type:  Uncategorized  |     Status:  new
    Component:  Uncategorized  |    Version:  1.4
     Severity:  Normal         |   Keywords:  max_length, FileField, fields
 Triage Stage:  Unreviewed     |  Has patch:  0
Easy pickings:  0              |      UI/UX:  0
-------------------------------+-------------------------------------------
 The following code in {{{django.db.models.fields.files}}} (line # 235 in
 master @ HEAD) is problematic.

 {{{
     def validate(self, value, model_instance):
         """
         Validates that the generated file name still fits within
 max_length.
         """
         # The generated file name stored in the database is generally
 longer
         # than the uploaded file name. Using the length of generated name
 in
         # the error message would be confusing. However, in the common
 case
         # (ie. upload_to='path/to/upload/dir'), the length of the
 generated
         # name equals the length of the uploaded name plus a constant.
 Thus
         # we can tell the user how much shorter the name should be
 (roughly).
         length = len(self.generate_filename(model_instance, value.name))
         if self.max_length and length > self.max_length:
             error_values = {'extra': length - self.max_length}
             raise ValidationError(self.error_messages['max_length'] %
 error_values)
 }}}

 Given the following:

 {{{
 def oops_asset_path(instance, filename):
     """
     Returns the upload path for a ``Oops.asset``.
     """
     return 'oops/user_{upk}/{dt}/{fn}'.format(
         upk=instance.user_id,
         dt=timezone.now().strftime('%Y_%j_%H_%M_%S_%f'),
         fn=re.sub(r'[^\w\.]', '_', filename).lower())


 class Oops(models.Model):
     asset = models.FileField(_(u'asset'), upload_to=oops_asset_path)

 }}}

 When an {{{Oops}}} instance is saved with the {{{asset}}} file name
 {{{the-best-file-name-ever.jpg}}}, it's converted to something like:

 {{{
 oops/user_3145/2012_178_00_16_02_738638/the_best_file_name_ever.jpg
 }}}

 which is expected. Then, when the {{{Oops}}} is saved again in a form
 (e.g., an inline model formset I use for multiple uploads) the above
 validation code runs the existing name through my {{{oops_asset_path}}},
 which returns:

 {{{
 
oops/user_3145/2012_178_00_16_03_457362/oops_user_3145_2012_178_00_16_02_738638_the_best_file_name_ever.jpg
 }}}

 This causes the {{{max_length}}} validation error, since the new name is
 clearly too long:

 {{{
 Filename is 7 characters too long.
 }}}

 The file name isn't changed permanently, but these erroneous validation
 errors are only avoided by increasing the field's {{{max_length}}}.

 I can't think of any solution to this that doesn't include either a
 database query or else some sort of annotation on the {{{FileField}}} by
 forms... both of which scare me.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/18515>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to