Home > database >  Can't Populate Database by excel file in Django ( Management Command )
Can't Populate Database by excel file in Django ( Management Command )

Time:02-05

Management Command (populatedb.py)

import pandas as pd

from django.core.management.base import BaseCommand from django.apps import apps

class Command(BaseCommand): help = "Creating model objects according the file path specified"

def add_arguments(self, parser):
    parser.add_argument('--path', type=str, help="file path")
    parser.add_argument('--model_name', type=str, help="model name")
    parser.add_argument('--app_name', type=str, help="django app name that the model is connected to")

def handle(self, *args, **options):
    file_path = options['path']
    _model = apps.get_model(options['app_name'], options['model_name'])
    df = pd.read_excel(file_path)
    header = list(df.columns)        

    for row in df:
        _object_dict = {key: value for key, value in zip(header, row)}
        _model.objects.create(**_object_dict)

Terminal Error:

ValueError: Cannot assign "'a'": "State.country" must be a "Country" instance.

Models.py

class State(TimeStampModel):
name = models.CharField(max_length=100)
country = models.ForeignKey(Country,on_delete=models.CASCADE)
image = models.ImageField(upload_to=path_and_rename)

def __str__(self) -> str:
    return f"{self.name}"

class Meta:
    db_table = 'states'
    unique_together = ('name', 'country',)

CodePudding user response:

You need to get the instance of country using state model. You can do something like this.

from django.apps import apps
from django.core.management.base import BaseCommand
import pandas as pd
import csv

class Command(BaseCommand):
    help = "Creating model objects according the file path specified"

    def add_arguments(self, parser):
        parser.add_argument('--path', type=str, help="file path", default=None)
        parser.add_argument('--model_name', type=str,
                            help="model name", default=None)
        parser.add_argument(
            '--app_name', type=str, help="django app name that the model is connected to", default=None)

    def handle(self, *args, **options):
        # print(options)
        file_path = options['path']
        if not file_path.endswith('.csv'):
            self.stdout.write('File "%s" is not csv type.' % file_path)
        _model = apps.get_model(options['app_name'], options['model_name'])

        with open(file_path, 'r') as csv_file:
            reader = csv.reader(csv_file, delimiter=',', quotechar='|')
            header = next(reader)
            for row in reader:
                _object_dict = {key: value for key, value in zip(header, row)}

                opts = _model._meta
                print(_object_dict)
                fields = [field for field in opts.get_fields() if not field.many_to_many and not field.one_to_many]
                # print('fields', fields)
                # other_fields = [field for field in opts.get_fields() if field.many_to_many or field.one_to_many ]
                other_fields = [field for field in opts.get_fields() if field.many_to_many or field.one_to_many or field.many_to_one]
                # print('other fields', other_fields)
                id = _object_dict.get('id')
                try:
                    obj = _model.objects.get(pk=id)
                    print('fetched obj', obj)
                    print('object already exists in database')
                    continue
                except _model.DoesNotExist:
                    try:
                        if other_fields:
                            for field in other_fields:
                                rel_model = opts.get_field(
                                    field.verbose_name).related_model #country model from state
                                try:
                                    rel_obj = rel_model.objects.get(
                                        id=_object_dict.get(field.verbose_name))
                                except rel_model.DoesNotExist:
                                    rel_obj = rel_model.objects.create(id=_object_dict.get(field.verbose_name))

                                _object_dict.update({field.verbose_name: rel_obj})
                                print(_object_dict)
                    except _model.DoesNotExist:
                        pass
                    obj = _model.objects.create(**_object_dict)
                    print('creating obj')
                except _model.MultipleObjectsReturned:
                    print('multiple entries returned for this id', id)
                    pass
  •  Tags:  
  • Related