Package: django-batch-sheet
django-batch-sheetMost of the projects we worked on needs a feature to upload data in batch, we always ended up write another code to handle
the Excel sheet and where each column shall go in the model, in the latest project we decided to handle it differently
and why write a django app that handles this like ModelForm handles models and surprisingly, it worked.FeaturesGenerate a Sheet from a Django model or a combination of models (through Combined Sheet),Add the validation rules for Choices, Foreign Keys, Integers automatically in Excel,Showing the required field in red by defaultSheet can be validated automatically and check withis_valid()Allow  overriding the behavior of  model in the class,Allow alot of functions to override the class behavior (row_preprocess,save,pre_load,post_process),Automatic Loading of the data in the sheet to the model.InstallInstall the packagepipinstalldjango-batch-sheetAdd it to INSTALLED_APPSINSTALLED_APPS=[...'batch_sheet'...]ExampleLet's assume that we have the following models with these rulesPatient can have multiple tests but saved once as aPatientObject.classTest(models.Model):name=models.CharField(max_length=50)def__str__(self):returnself.nameclassGender(models.Model):name=models.CharField(max_length=50)def__str__(self):returnself.nameclassPatient(models.Model):name=models.CharField(max_length=50,verbose_name="Patient Name")MRN=models.CharField(max_length=50)gender=models.ForeignKey(Gender,on_delete=models.PROTECT,null=True,verbose_name="Gender")date_of_birth=models.DateField(null=True,blank=True,verbose_name="Birth Date")date_admitted=models.DateField(auto_now_add=True,auto_created=True)lastUpdate=models.DateTimeField(auto_now=True)classRequestedTest(models.Model):patient=models.ForeignKey(Patient,on_delete=models.CASCADE)test=models.ForeignKey(Test,on_delete=models.PROTECT,verbose_name="Test")sample_date=models.DateField(auto_now_add=True,auto_created=True)sample_type=models.CharField(max_length=50,verbose_name="Sample Type",choices=(('Blood','Blood'),('DNA','DNA')))lastUpdate=models.DateTimeField(auto_now_add=True)We want to combine both Models in on sheet, so we put the patient information with the requested test in one row.So For Patient, we will implement the classPatientSheetas followsclassPatientSheet(Sheet):defsave(self,obj:Patient,row_objs:dict):"""Lets handle the save manually to check if the MRN exists"""patient=Patient.objects.filter(MRN=obj.MRN)ifpatient.exists():p=patient[0]else:p=objp.save()returnpclassMeta:exclude=('id','date_admitted','lastUpdate')Model=Patientobj_name="patient"title_header=TrueFor the Meta attributes, please go to the Meta Attributes sectionsFor RequestedTest Sheet, it goes like thisclassRequestedTestSheet(Sheet):defsave(self,obj,row_objs):patient=row_objs.get('patient')ifpatientisNone:returnNoneelse:obj.patient=patientobj.save()returnobjclassMeta:exclude=('id','sample_date','lastUpdate')validation_exclude=('patient',)title_header=TrueModel=RequestedTestNow Lets combine them in one sheetclassTestSheet(CombinedSheet):patient=PatientSheet()test=RequestedTestSheet()Now Let's Generate The sheet$ python manage.py generate_sheet --xls App.xls --sheet test_app.sheets.TestSheetThis will the file toApp.xlsin the folder, now, lets openApp.xlsWe got the dropdown automatically, based on the value in the database.Meta OptionsClassMeta:rows_count=10# Number of rows to apply validations oncolumns=()# Columns to add from the Model to the sheetexclude=()# Columns to excludeModel=None# Model to scanraw_cols=[]# Foreign Key Field that shouldn't be set as dropdowntitle_header=False# Make the titles as "First Name"validation_exclude=[]# Don't validate these field, important in case of objects relationshipobject_name=None# The name of the object saved, important in case of Combined Sheet.