How to generate composite unique key like frappe

may i know how to generate random or composite unique key values for name field of child table

i asked this when i try to insert values to student batch student table

frappe.db.sql("""insert intotabStudent Batch Student (parent,student,parentfield,parenttype,student_name,name) values (%s,%s,%s,%s,%s,%s)""",(student_batch,id,"students","Student Batch",st_name))

i was getting an error

Traceback (most recent call last):
  File "/home/shahid/think/frappe-think/apps/frappe/frappe/app.py", line 55, in application
    response = frappe.handler.handle()
  File "/home/shahid/think/frappe-think/apps/frappe/frappe/handler.py", line 19, in handle
    execute_cmd(cmd)
  File "/home/shahid/think/frappe-think/apps/frappe/frappe/handler.py", line 40, in execute_cmd
    ret = frappe.call(method, **frappe.form_dict)
  File "/home/shahid/think/frappe-think/apps/frappe/frappe/__init__.py", line 898, in call
    return fn(*args, **newargs)
  File "/home/shahid/think/frappe-think/apps/erpnext/erpnext/schools/doctype/student_applicant/student_applicant.py", line 85, in add_selected_student_to_childtable
    print frappe.db.sql("""insert into `tabStudent Batch Student` (`parent`,`student`,`parentfield`,`parenttype`,`student_name`,`name`) values (%s,%s,%s,%s,%s,%s)""",(student_batch,id,"students","Student Batch",st_name,'xxx'))
  File "/home/shahid/think/frappe-think/apps/frappe/frappe/database.py", line 137, in sql
    self._cursor.execute(query, values)
  File "/home/shahid/think/frappe-think/env/lib/python2.7/site-packages/MySQLdb/cursors.py", line 205, in execute
    self.errorhandler(self, exc, value)
  File "/home/shahid/think/frappe-think/env/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
IntegrityError: (1062, "Duplicate entry 'xxx' for key 'PRIMARY'")

before i was using this code

                # doc = frappe.get_doc({
		# 			"doctype": "Student Batch Student",
		# 			"parent": student_batch,
		# 			"parentfield":"students",
		# 			"parenttype":"Student Batch",
		# 			"student_name":name,
		# 			"student": id

		# 	})
		# if doc.insert():
		# 	return 'success'

but this code runs only once if it is in for loop

and i was getting an error in terminal

Error on request:
Traceback (most recent call last):
  File "/home/shahid/think/frappe-think/env/lib/python2.7/site-packages/werkzeug/serving.py", line 209, in run_wsgi
    execute(self.server.app)
  File "/home/shahid/think/frappe-think/env/lib/python2.7/site-packages/werkzeug/serving.py", line 200, in execute
    write(data)
  File "/home/shahid/think/frappe-think/env/lib/python2.7/site-packages/werkzeug/serving.py", line 168, in write
    self.send_header(key, value)
  File "/usr/lib64/python2.7/BaseHTTPServer.py", line 401, in send_header
    self.wfile.write("%s: %s\r\n" % (keyword, value))
IOError: [Errno 32] Broken pipe

Maybe because the value of name (student) field is same every time?

@netchampfaris no it is differerent i checked it

var error = ;
var duplicate = ;
frappe.listview_settings[‘Student Applicant’] = {
add_fields: [ “application_status”, ‘paid’],
has_indicator_for_draft: 1,
get_indicator: function(doc) {
if (doc.paid) {
return [(“Paid”), “green”, “paid,=,Yes”];
}
else if (doc.application_status==“Applied”) {
return [
(“Applied”), “orange”, “application_status,=,Applied”];
}
else if (doc.application_status==“Approved”) {
return [(“Approved”), “green”, “application_status,=,Approved”];
}
else if (doc.application_status==“Rejected”) {
return [
(“Rejected”), “red”, “application_status,=,Rejected”];
}
else if (doc.application_status==“Admitted”) {
return [(“Admitted”), “blue”, “application_status,=,Admitted”];
}
}
};
$.extend(frappe.listview_settings[‘Student Applicant’], {
onload: function(listview) {
// adds new menu item to the menu button(blue colored)
listview.page.add_menu_item(
(“Add To Student Batch”), function() {

  	var selected = listview.get_checked_items() || [];
  	// calls to python function which returns details of checked students  from 
  	// student table when Bulk Summit function is clicked
  	if(getIdsFromList().length === 0){
  			frappe.throw("Minimum One Student Required");
  	}
  	test = [];
  	showDilogueBox();
  	// selectStudentIdFromStudentDocType(listview);
  	
  	});

}
});
// get id of checked students
var getIdsFromList = function(){
var docids = null;
var route = frappe.get_route();
var len = route.length;
if (len > 1 && route[0] === “List”){
var doctype = route[1];
var page = [route[0], doctype].join(“/”);
docids = getCheckedNames(page);
}

return docids;
};
// get checked item
getChecked = function(name){
return $(frappe.pages[name]).find(“input:checked”);
};

getCheckedNames = function(page){
var names = ;
var checked = getChecked(page);
var elems_a = checked.siblings(“a”);
elems_a.each(function(i,el){
var t = unescape($(el).attr(“href”)).slice(1);
var s = t.split(“/”);
names.push(s[s.length - 1]);
});

return names;
};

var showDilogueBox = function(){
var dialog = new frappe.ui.Dialog({
title: __(“Select a student batch”),
fields: [
{“fieldtype”: “Link”, “label”: __(“Please select a Batch to add select students to batch”), “fieldname”: “student_name”,
“reqd”: 1, “options”:“Student Batch” },
{“fieldtype”: “Button”, “label”: __(“Add To Batch”), “fieldname”: “update1”},
{“fieldtype”: “Button”, “label”: __(“Add To New Batch”), “fieldname”: “update”}
]
});
dialog.fields_dict.update1.input.onclick = function() {
var batch_name = $(“input[data-fieldname=‘student_name’]”).val();
selectStudentIdFromStudentDocType(batch_name);
}
dialog.fields_dict.update.input.onclick = function() {
AddStudentToNewBatch();
}
dialog.show();

};

var set_error = function(error){
return error;
}
var selectStudentIdFromStudentDocType = function(batch_name){
frappe.call({
method: “erpnext.schools.doctype.student_applicant.student_applicant.get_name_if_enrolled_empty_if_not”,
args: {
name_of_student: JSON.stringify(getIdsFromList())
},
async: false,
callback: function(r){
if(!r.exec)
{
stud_id = ;
stud_name = ;
x = 0;
res = JSON.parse(r.message);
var no_of_res = JSON.parse(r.message).length;
for (i=0;i<no_of_res;i++){
// checks and counts selected students who are not enrolled
if(res[i].length == 0){
x = x+1;
}else{
stud_id.push(res[i][0].name);
stud_name.push(res[i][0].title);
}
}
if(x>0){
frappe.throw(“Please Enroll the Selected Student Applicants before adding to a Batch”);
}
console.log(stud_id);
frappe.call({
method: “erpnext.schools.doctype.student_applicant.student_applicant.add_selected_student_to_childtable”,
args: {
stud_id:JSON.stringify(stud_id),
stud_name:JSON.stringify(stud_name),
student_batch:batch_name
},
async:true,
callback:function(r){
if(!r.exec){
if(r.message === ‘success’)
{
location.reload();
frappe.set_route(“Form”, “Student Batch”,batch_name);
}
}
}
});
}

  }

});
};

var AddStudentToNewBatch = function(){
frappe.call({
method: “erpnext.schools.doctype.student_applicant.student_applicant.get_name_if_enrolled_empty_if_not”,
args: {
name_of_student: JSON.stringify(getIdsFromList())
},
callback: function(r){
if(!r.exec)
{
stud_id = ;
stud_name = ;
x = 0;
res = JSON.parse(r.message);
var no_of_res = JSON.parse(r.message).length;
for (i=0;i<no_of_res;i++){
// checks and counts selected students who are not enrolled
if(res[i].length == 0){
x = x+1;
}else{
stud_id.push(res[i][0].name);
stud_name.push(res[i][0].title);
}
}
if(x>0){
frappe.throw(“Please Enroll the Selected Student Applicants before adding to a Batch”);
}
frappe.model.with_doctype(“Student Batch”, function() {
var tlb = frappe.model.get_new_doc(“Student Batch”);
$.each(stud_id, function(i, d) {
var detail = frappe.model.get_new_doc(“Student Batch Student”, tlb,
“students”);
$.extend(detail, {
“student”: d,
“student_name”: stud_name[i],
});
})
frappe.set_route(“Form”, “Student Batch”,tlb.name);
})
}
}
});
};

above is js side which calls below function on server side

def check_for_duplicate(stud_id,student_batch):
	duplicate_student_list = []
	for id in json.loads(stud_id):
		if frappe.db.get_list("Student Batch Student",filters={"parent":student_batch,"student":id},fields=['student','student_name']):
				frappe.msgprint("Some Students are already exist in the selected batch.Please remove them and try again.")
				duplicate_student_list.append(id)
	return duplicate_student_list

@frappe.whitelist()
def add_selected_student_to_childtable(stud_id,stud_name,student_batch):
	# used if else because of reload method in js it will reload even we perform frappe.throw
	if not (check_for_duplicate(stud_id,student_batch)):
		for id,st_name  in zip(json.loads(stud_id),json.loads(stud_name)):
			# complex_name = id_generator()
			print frappe.db.sql("""insert into `tabStudent Batch Student` (`parent`,`student`,`parentfield`,`parenttype`,`student_name`) values (%s,%s,%s,%s,%s)""",(student_batch,id,"students","Student Batch",st_name))
			# doc = frappe.get_doc({
			# 			"doctype": "Student Batch Student",
			# 			"parent": student_batch,
			# 			"parentfield":"students",
			# 			"parenttype":"Student Batch",
			# 			"student_name":name,
			# 			"student": id

			# 	})
			# if doc.insert():
			# 	return 'success'
	return "duplicate"

this is the entire code

The proper way to insert child table values in a doc is

doc = frappe.get_doc('Student Batch', batch_name)
doc.append('students', {
  'student_name': name,
  'student': id
})
doc.save()
2 Likes

@netchampfaris it worked
you are awesome. :blush::clap::thumbsup:

thanks a lot