Validation for File Types in Web Forms

The following code works fine in a doctype but not in a web form. This is because the attached_to_doctype and attached_to_field values are not populated when uploading through the web form.

def validate_file_type(doc, method):
    if doc.attached_to_doctype == 'Test Form':
        if doc.attached_to_field in ["photograph", "signature"]:
            if not doc.file_name.lower().endswith(".jpg") or not doc.file_name.lower().endswith(".jpeg"):
                frappe.throw("Only <b>JPG/JPEG</b> file Allowed")
        else:
            if not doc.file_name.lower().endswith(".pdf"):
                frappe.throw("Only <b>PDF</b> file Allowed")

Requirement:

  • For fields like photograph and signature, the uploaded file should always be in JPG/JPEG format.
  • For all other attach fields, only PDF files should be allowed.

How can I achieve this validation for my web form where attached_to_doctype and attached_to_field are not available during file upload?

Looking for same thing exactly … hope someone can help!

workaround by handling from backend:

In hooks.py of your customp application

override_doctype_class = {
# “File”: “custom_app.overrides.doctype.file.CustomFile”,
}

And in file.py add the below code:

import mimetypes
import frappe
from frappe import _
from frappe.core.doctype.file.exceptions import MaxFileSizeReachedError
from frappe.core.doctype.file.file import File

class CustomFile(File):
def check_max_file_size(self):

    # Predefined file size limits by category (in bytes)
    file_type_limits = {
        "image": 5 * 1024 * 1024,   # 5 MB for image files
        "document": 10 * 1024 * 1024,  # 10 MB for document files
        "video": 30 * 1024 * 1024,   # 30 MB for video files
    }

    # Guess the MIME type of the file
    file_type = mimetypes.guess_type(self.file_name)[0]
    if not file_type:
        # If MIME type is undetectable, raise an error
        frappe.throw(_("Could not determine file type from MIME type."))

    # Determine the file's category based on MIME type
    if file_type.startswith("image"):
        file_category = "image"
    elif file_type.startswith("application"):
        # Check for common document types
        if any(file_type.startswith(prefix) for prefix in [
            "application/pdf", 
            "application/msword", 
            "application/vnd.ms-excel",]):
            file_category = "document"
    elif file_type.startswith("video"):
        file_category = "video"
    else:
        # If file type is unsupported, raise an error
        frappe.throw(_("Unsupported file type detected: {0}").format(file_type))

    # Get the file content size in bytes
    file_size = len(self.get("content") or b"")  # Default to empty byte string if no content

    # Check if the file size exceeds the maximum allowed limit for the detected category
    if file_category and file_size > file_type_limits.get(file_category, 0):
        # Raise error if file exceeds limit
        max_size_mb = file_type_limits[file_category] / (1024 * 1024)  # Convert bytes to MB
        msg = _("File size exceeds the maximum allowed limit of {0} MB").format(max_size_mb)
        frappe.throw(msg, exc=MaxFileSizeReachedError)

    return file_size  # Return the file size if it's within limits