@@ -14,7 +14,7 @@ from frappe.model.document import Document
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.desk.notifications import delete_notification_count_for
from frappe.desk.notifications import delete_notification_count_for
from frappe.modules import make_boilerplate
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
import frappe.website.render
class InvalidFieldNameError(frappe.ValidationError): pass
class InvalidFieldNameError(frappe.ValidationError): pass
@@ -385,9 +385,10 @@ def validate_fields(meta):
1. There are no illegal characters in fieldnames
1. There are no illegal characters in fieldnames
2. If fieldnames are unique.
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.
7. `Check` type field has default as 0 or 1.
8. `Dynamic Links` are correctly defined.
8. `Dynamic Links` are correctly defined.
9. Precision is set in numeric fields and is between 1 & 6.
9. Precision is set in numeric fields and is between 1 & 6.
@@ -406,6 +407,9 @@ def validate_fields(meta):
if len(duplicates) > 1:
if len(duplicates) > 1:
frappe.throw(_("Fieldname {0} appears multiple times in rows {1}").format(fieldname, ", ".join(duplicates)))
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):
def check_illegal_mandatory(d):
if (d.fieldtype in no_value_fields) and d.fieldtype!="Table" and d.reqd:
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))
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),
frappe.throw(_("Sort field {0} must be a valid fieldname").format(fieldname),
InvalidFieldNameError)
InvalidFieldNameError)
fields = meta.get("fields")
fields = meta.get("fields")
fieldname_list = [d.fieldname for d in fields]
fieldname_list = [d.fieldname for d in fields]
@@ -598,6 +601,7 @@ def validate_fields(meta):
d.fieldname = d.fieldname.lower()
d.fieldname = d.fieldname.lower()
check_illegal_characters(d.fieldname)
check_illegal_characters(d.fieldname)
check_unique_fieldname(d.fieldname)
check_unique_fieldname(d.fieldname)
check_fieldname_length(d.fieldname)
check_illegal_mandatory(d)
check_illegal_mandatory(d)
check_link_table_options(d)
check_link_table_options(d)
check_dynamic_link_options(d)
check_dynamic_link_options(d)
@@ -766,3 +770,11 @@ def init_list(doctype):
doc = frappe.get_meta(doctype)
doc = frappe.get_meta(doctype)
make_boilerplate("controller_list.js", doc)
make_boilerplate("controller_list.js", doc)
make_boilerplate("controller_list.html", 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))