{"id":22295936,"url":"https://github.com/mkalioby/django-batch-sheet","last_synced_at":"2025-07-20T14:32:58.574Z","repository":{"id":61621861,"uuid":"448514068","full_name":"mkalioby/django-batch-sheet","owner":"mkalioby","description":"Generate Excel sheets to batch upload to Database","archived":false,"fork":false,"pushed_at":"2023-03-16T10:30:55.000Z","size":4796,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-07-20T10:06:33.599Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"CSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mkalioby.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-16T09:52:29.000Z","updated_at":"2024-11-20T16:48:46.000Z","dependencies_parsed_at":"2023-01-22T01:15:22.996Z","dependency_job_id":null,"html_url":"https://github.com/mkalioby/django-batch-sheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mkalioby/django-batch-sheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkalioby%2Fdjango-batch-sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkalioby%2Fdjango-batch-sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkalioby%2Fdjango-batch-sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkalioby%2Fdjango-batch-sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkalioby","download_url":"https://codeload.github.com/mkalioby/django-batch-sheet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkalioby%2Fdjango-batch-sheet/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266140191,"owners_count":23882629,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-03T17:43:37.620Z","updated_at":"2025-07-20T14:32:58.558Z","avatar_url":"https://github.com/mkalioby.png","language":"CSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"## django-batch-sheet\n\nMost of the projects we worked on needs a feature to upload data in batch, we always ended up writing another code to handle \nthe Excel sheet and where each column shall go in the model(s), in the latest project we decided to handle it differently\nand that is why we wrote a django app that handles this like ModelForm handles models and surprisingly, it worked.\n\n## Features\n* Generate a Sheet from a Django model or a combination of models (through Combined Sheet),\n* Add the validation rules for Choices, Foreign Keys, Integers automatically in Excel,\n* Showing the required field in red by default\n* Sheet can be validated automatically and check with `is_valid()`\n* Allow  overriding the behavior of  model in the class,\n* Allow alot of functions to override the class behavior (`row_preprocess`,`save`,`pre_load`,`post_process`),\n* Automatic Loading of the data in the sheet to the model.\n\n## Install\n1. Install the package\n```sh\npip install django-batch-sheet\n```\n2. Add it to INSTALLED_APPS\n```python\nINSTALLED_APPS=[\n...\n'batch_sheet'\n...\n]\n```\n\n## Example\n\nLet's assume that we have the following models with these rules\n\n* Patient can have multiple tests but saved once as a `Patient` Object.\n\n```python\nclass Test(models.Model):\n    name = models.CharField(max_length=50)\n\n    def __str__(self):\n        return self.name\n\n\nclass Gender (models.Model):\n    name = models.CharField(max_length=50)\n\n    def __str__(self):\n        return self.name\n\nclass Patient(models.Model):\n    name = models.CharField(max_length=50,verbose_name=\"Patient Name\")\n    MRN = models.CharField(max_length=50)\n    gender= models.ForeignKey(Gender,on_delete=models.PROTECT,null=True, verbose_name=\"Gender\")\n    date_of_birth = models.DateField(null=True,blank=True,verbose_name=\"Birth Date\")\n    date_admitted = models.DateField(auto_now_add=True,auto_created=True)\n    lastUpdate = models.DateTimeField(auto_now=True)\n\n\nclass RequestedTest(models.Model):\n    patient = models.ForeignKey(Patient,on_delete=models.CASCADE)\n    test = models.ForeignKey(Test,on_delete=models.PROTECT,verbose_name=\"Test\")\n    sample_date = models.DateField(auto_now_add=True,auto_created=True)\n    sample_type = models.CharField(max_length=50, verbose_name=\"Sample Type\",choices=(('Blood','Blood'),('DNA','DNA')))\n    lastUpdate = models.DateTimeField(auto_now_add=True)\n```\n\nWe want to combine both Models in on sheet, so we put the patient information with the requested test in one row.\n\nSo For Patient, we will implement the class `PatientSheet` as follows\n\n```python\nclass PatientSheet(Sheet):\n    def save(self, obj:Patient, row_objs:dict):\n        \"\"\"Lets handle the save manually to check if the MRN exists\"\"\"\n        patient = Patient.objects.filter(MRN = obj.MRN)\n        if patient.exists():\n            p = patient[0]\n        else:\n            p = obj\n            p.save()\n        return p\n    class Meta:\n        exclude=('id','date_admitted','lastUpdate')\n        Model = Patient\n        obj_name = \"patient\"\n        title_header = True\n```\nFor the Meta attributes, please go to the Meta Attributes sections\n\nFor RequestedTest Sheet, it goes like this \n\n```python\nclass RequestedTestSheet(Sheet):\n    def save(self,obj,row_objs):\n        patient = row_objs.get('patient')\n        if patient is None:\n            return None\n        else:\n            obj.patient = patient\n            obj.save()\n            return obj\n\n    class Meta:\n        exclude =('id','sample_date','lastUpdate')\n        validation_exclude = ('patient',)\n        title_header = True\n        Model = RequestedTest\n```\n\nNow Lets combine them in one sheet\n\n```python\nclass TestSheet(CombinedSheet):\n    patient = PatientSheet()\n    test = RequestedTestSheet()\n```\n\nNow Let's Generate The sheet\n\n```\n$ python manage.py generate_sheet --xls App.xls --sheet test_app.sheets.TestSheet\n```\nThis will the file to `App.xls` in the folder, now, lets open `App.xls`\n\n![docs/imgs/xls.png](docs/imgs/xls.png)\n\nWe got the dropdown automatically, based on the value in the database.\n\n## Meta Options\n```python\n    Class Meta:\n        rows_count = 10              # Number of rows to apply validations on\n        columns = ()                 # Columns to add from the Model to the sheet\n        exclude = ()                 # Columns to exclude\n        Model = None                 # Model to scan\n        raw_cols = []                # Foreign Key Field that shouldn't be set as dropdown\n        title_header = False         # Make the titles as \"First Name\"\n        validation_exclude=[]        # Don't validate these field, important in case of objects relationship  \n        object_name = None           # The name of the object saved, important in case of Combined Sheet.\n            \n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkalioby%2Fdjango-batch-sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkalioby%2Fdjango-batch-sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkalioby%2Fdjango-batch-sheet/lists"}