Opened 3 years ago

Closed 3 years ago

#32852 closed Bug (invalid)

Attribute error for missing content_type on File object for modeladmin change request

Reported by: Aiven Timptner Owned by: nobody
Component: File uploads/storage Version: 3.2
Severity: Normal Keywords: content_type
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I've got a model with a FileField and the corresponding admin page created with modeladmin. To validate the file type and only allow PDFs I wrote a custom validator which checks the content_type attribute on user (staff) uploads. When objects are created or the file itself get changed everything works as expected. But if I change some others fields on the model I receive an AttributeError.

def validate_file_extension(value: File):
    """Check if uploaded file content is pdf"""
    if value.file.content_type != 'application/pdf':
        raise ValidationError("Only PDF are allowed")


def user_directory_path(instance: File, filename: str) -> str:
    """Return a unix-like storage path as string with random file name"""
    filename = token_urlsafe(5) + '.pdf'
    filepath = f"jobs/{filename}"
    if Job.objects.filter(file=filepath).exists():
        return user_directory_path(instance, filename)
    return filepath


class Job(models.Model):
    title = models.CharField(max_length=250)
    description = models.TextField()
    file = models.FileField(upload_to=user_directory_path, validators=[validate_file_extension], blank=True, null=True)
    expired_on = models.DateTimeField(blank=True, null=True)
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

For now I solved it by ignoring AttributeErrors on validation

class Job(models.Model):
    title = models.CharField(max_length=250)
    description = models.TextField()
    file = models.FileField(upload_to=user_directory_path, validators=[validate_file_extension], blank=True, null=True)
    expired_on = models.DateTimeField(blank=True, null=True)
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

    def clean_fields(self, exclude=None):
        try:
            super().clean_fields(exclude=exclude)
        except AttributeError:
            # Handle missing content_type on file object
            pass

Change History (5)

comment:1 by Aiven Timptner, 3 years ago

Cc: Aiven Timptner added

comment:2 by Aiven Timptner, 3 years ago

Cc: Aiven Timptner removed

comment:3 by Tim Graham, 3 years ago

What's the traceback? Can you explain why Django is at fault?

in reply to:  description comment:4 by João Freires, 3 years ago

Replying to Aiven Timptner:

I've got a model with a FileField and the corresponding admin page created with modeladmin. To validate the file type and only allow PDFs I wrote a custom validator which checks the content_type attribute on user (staff) uploads. When objects are created or the file itself get changed everything works as expected. But if I change some others fields on the model I receive an AttributeError.

Yes, all of your validators will be called when you save a model. And your a assuming that your file has a content_type attribute, but only the file sent to a request has a content type(the TemporaryUploadedFile), when you change your model and keep your current file, all of your validators will receive a File and not TemporaryUploadedFile, and the File object does not have a content type.

You can assume that all pdf files follow the pattern *.pdf and check if the filename ends with the pattern and/or check the types of File, something like:

def validate_file_extension(value: File):
    """Check if uploaded file content is pdf"""
    if not value.file.name.endswith(".pdf"):
        raise ValidationError("Only PDF are allowed")

comment:5 by Carlton Gibson, 3 years ago

Resolution: invalid
Status: newclosed

This looks like a support issue. Please see TicketClosingReasons/UseSupportChannels for appropriate locations.

Note: See TracTickets for help on using tickets.
Back to Top