diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index a52396a8e3..465dacf63f 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -14,7 +14,7 @@ from frappe.model.document import Document from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.desk.notifications import delete_notification_count_for from frappe.modules import make_boilerplate -from frappe.model.db_schema import validate_column_name +from frappe.model.db_schema import validate_column_name, validate_column_length import frappe.website.render class InvalidFieldNameError(frappe.ValidationError): pass @@ -385,9 +385,10 @@ def validate_fields(meta): 1. There are no illegal characters in fieldnames 2. If fieldnames are unique. - 3. Fields that do have database columns are not mandatory. - 4. `Link` and `Table` options are valid. - 5. **Hidden** and **Mandatory** are not set simultaneously. + 3. Validate column length. + 4. Fields that do have database columns are not mandatory. + 5. `Link` and `Table` options are valid. + 6. **Hidden** and **Mandatory** are not set simultaneously. 7. `Check` type field has default as 0 or 1. 8. `Dynamic Links` are correctly defined. 9. Precision is set in numeric fields and is between 1 & 6. @@ -406,6 +407,9 @@ def validate_fields(meta): if len(duplicates) > 1: frappe.throw(_("Fieldname {0} appears multiple times in rows {1}").format(fieldname, ", ".join(duplicates))) + def check_fieldname_length(fieldname): + validate_column_length(fieldname) + def check_illegal_mandatory(d): if (d.fieldtype in no_value_fields) and d.fieldtype!="Table" and d.reqd: frappe.throw(_("Field {0} of type {1} cannot be mandatory").format(d.label, d.fieldtype)) @@ -581,7 +585,6 @@ def validate_fields(meta): frappe.throw(_("Sort field {0} must be a valid fieldname").format(fieldname), InvalidFieldNameError) - fields = meta.get("fields") fieldname_list = [d.fieldname for d in fields] @@ -598,6 +601,7 @@ def validate_fields(meta): d.fieldname = d.fieldname.lower() check_illegal_characters(d.fieldname) check_unique_fieldname(d.fieldname) + check_fieldname_length(d.fieldname) check_illegal_mandatory(d) check_link_table_options(d) check_dynamic_link_options(d) @@ -766,3 +770,11 @@ def init_list(doctype): doc = frappe.get_meta(doctype) make_boilerplate("controller_list.js", doc) make_boilerplate("controller_list.html", doc) + +def check_if_fieldname_conflicts_with_methods(doctype, fieldname): + doc = frappe.get_doc({"doctype": doctype}) + method_list = [method for method in dir(doc) if callable(getattr(doc, method))] + + if fieldname in method_list: + frappe.throw(_("Fieldname {0} conflicting with meta object").format(fieldname)) + diff --git a/frappe/custom/doctype/custom_field/custom_field.js b/frappe/custom/doctype/custom_field/custom_field.js index a74e7bd640..c430d12752 100644 --- a/frappe/custom/doctype/custom_field/custom_field.js +++ b/frappe/custom/doctype/custom_field/custom_field.js @@ -11,7 +11,7 @@ frappe.ui.form.on('Custom Field', { ['DocType', 'issingle', '=', 0], ]; if(frappe.session.user!=="Administrator") { - filters.push(['DocType', 'module', '!=', 'Core']) + filters.push(['DocType', 'module', 'not in', ['Core', 'Custom']]) } return { "filters": filters diff --git a/frappe/custom/doctype/custom_field/custom_field.py b/frappe/custom/doctype/custom_field/custom_field.py index 57ea7a2b0b..2d0ad96c26 100644 --- a/frappe/custom/doctype/custom_field/custom_field.py +++ b/frappe/custom/doctype/custom_field/custom_field.py @@ -39,6 +39,10 @@ class CustomField(Document): if not self.fieldname: frappe.throw(_("Fieldname not set for Custom Field")) + if not self.flags.ignore_validate: + from frappe.core.doctype.doctype.doctype import check_if_fieldname_conflicts_with_methods + check_if_fieldname_conflicts_with_methods(self.dt, self.fieldname) + def on_update(self): frappe.clear_cache(doctype=self.dt) if not self.flags.ignore_validate: diff --git a/frappe/custom/doctype/customize_form/customize_form.js b/frappe/custom/doctype/customize_form/customize_form.js index 77b489241b..ea9835525b 100644 --- a/frappe/custom/doctype/customize_form/customize_form.js +++ b/frappe/custom/doctype/customize_form/customize_form.js @@ -15,7 +15,7 @@ frappe.ui.form.on("Customize Form", { ['DocType', 'custom', '=', 0], ['DocType', 'name', 'not in', 'DocType, DocField, DocPerm, User, Role, Has Role, \ Page, Has Role, Module Def, Print Format, Report, Customize Form, \ - Customize Form Field'], + Customize Form Field, Property Setter, Custom Field, Custom Script'], ['DocType', 'restrict_to_domain', 'in', frappe.boot.active_domains] ] }; diff --git a/frappe/model/db_schema.py b/frappe/model/db_schema.py index b5d76aead6..2bad7a4d1b 100644 --- a/frappe/model/db_schema.py +++ b/frappe/model/db_schema.py @@ -563,6 +563,13 @@ def validate_column_name(n): frappe.throw(_("Fieldname {0} cannot have special characters like {1}").format(cstr(n), special_characters), InvalidColumnName) return n +def validate_column_length(fieldname): + """ In MySQL maximum column length is 64 characters, + ref: https://dev.mysql.com/doc/refman/5.5/en/identifiers.html""" + + if len(fieldname) > 64: + frappe.throw(_("Fieldname is limited to 64 characters ({0})").format(fieldname)) + def remove_all_foreign_keys(): frappe.db.sql("set foreign_key_checks = 0") frappe.db.commit()