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
