'Why I am getting a single array object instead of all array values in Django rest framework?
I am using Django rest framework for API and pandas to parse excel file. But my Django model takes only the last row of excel file and returns it. I want all rows to be posted and returned. Here is my code.
models.py
class BusinessImpact(models.Model, ModelWithCreateFromDict):
client = models.ForeignKey(
accounts_models.Client, on_delete=models.CASCADE)
business_process = models.ForeignKey(
BusinessProcess, on_delete=models.CASCADE)
hierarchy = models.CharField(max_length=255)
business_assets = models.CharField(max_length=255)
asset_name = models.CharField(max_length=255)
vendors = models.CharField(max_length=255)
product = models.CharField(max_length=255)
version = models.CharField(max_length=10)
cpe = models.CharField(max_length=255)
asset_type = models.CharField(max_length=10)
asset_categorization = models.CharField(max_length=255)
asset_risk = models.CharField(max_length=50)
_regulations = models.TextField(blank=True)
_geolocation = models.TextField(blank=True)
def __str__(self) -> str:
return self.hierarchy + " - " + self.business_assets
@property
def regulations(self) -> List[str]:
return self._regulations.split(",")
@property
def geolocation(self) -> List[str]:
return self._geolocation.split(",")
excel_titles = {
"hierarchy": "Hierarchy",
"business_assets": "Business Assets",
"asset_name": "Asset Name",
"vendors": "Vendors",
"product": "Product",
"version": "Version",
"cpe": "CPE",
"asset_type": "Asset Type",
"asset_categorization": "Asset Categorization",
"asset_risk": "Asset Risk",
"_regulations": "Regulations",
"_geolocation": "GeoLocation",
}
important_fields = ["hierarchy", "business_assets", "asset_name"]
ModelWithCreateFromDict.py
from utils.extended_models import helpers
class ModelWithCreateFromDict:
@classmethod
def all_important_fields_are_provided(cls, dict):
if not hasattr(cls, 'important_fields'): return
res = True
for field in getattr(cls, 'important_fields'):
if dict.get(field) == None or dict.get(field) == "":
# raise Exception("BY MIKE := {} is important field and not been provided".format(field))
print("BY MIKE := {} is important field and not been provided".format(field))
res = False
return res
@classmethod
def create_obj_form_dict(cls, dict):
data = {}
arr_data = {}
# This has side effect it might create objects on db if
# it can't get them create_object_with_name method
for val in dict:
try:
field = cls._meta.get_field(val)
field_type = field.get_internal_type()
if field_type != "ArrayReferenceField" and field_type != "ForeignKey":
data[val] = dict[val]
elif field_type == "ForeignKey":
data[val] = helpers.get_or_create_foreignkey_object_by_name_or_id(
field.related_model, dict[val]
)
elif field_type == "ArrayReferenceField":
arr_data[val] = helpers.get_array_objects_by_name(
field.related_model, dict[val]
)
# ADD CASE FOR ArrayField
except Exception as e:
print(e)
if not cls.all_important_fields_are_provided(data):
# NOTE if all important fields are not on dict ignore that row
return
try:
obj = cls.objects.create(**data)
for ad in arr_data:
many_to_many_field = getattr(obj, ad)
for arr_val in arr_data[ad]:
many_to_many_field.add(arr_val)
return obj
except Exception as e:
# NOTE if DB object is not able to be created from dict for some reason ignore that dict
print(e)
return None
ExcelHandlingView
import time
from accounts import models
from utils.extended_models.ExtendedModel
import ModelWithCreateFromDict
class ExcelHandlingView:
@classmethod
def isNaN(cls, num):
return num != num
@classmethod
def get_value_or_none(cls, val):
if cls.isNaN(val):
return None
return str(val).strip()
@classmethod
def get_excel_fields(cls, dict):
res = []
for v in dict.values():
res.append(v)
return res
@classmethod
def can_model_handle_ExcelHandlingView(cls, model):
if not hasattr(model, 'excel_titles'):
raise Exception(
"`BY MIKE` := {} has got no excel_titles defined".format(model))
if not hasattr(model, 'create_obj_form_dict'):
raise Exception("`BY MIKE` := {} is not a child of {}".format(
model, ModelWithCreateFromDict))
@classmethod
def create_model_object(cls, model, row, other_dict_data={}):
# cls.delete_every_recore_on_that_model(model)
data = other_dict_data
for d in model.excel_titles:
data[d] = cls.get_value_or_none(row.get(model.excel_titles[d]))
return model.create_obj_form_dict(data)
views.py
class UploadBusinessImpactExcelByClientAdmin(APIView, ExcelHandlingView):
def post(self, request):
self.can_model_handle_ExcelHandlingView(models.BusinessImpact)
serializer = serializers.ExcelFileAndBusinessProcessUploader(
data=request.data)
if serializer.is_valid():
data = serializer.validated_data
file = data.get("file")
client = request.user.client
business_process_id = data.get("business_process")
try:
business_process = get_business_process_by_client(
client, business_process_id
)
except (
models.BusinessProcess.DoesNotExist,
accountModels.Client.DoesNotExist,
) as e:
return Response(
"business process or client does not exist",
status=status.HTTP_404_NOT_FOUND,
)
if (
file.content_type
== "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
):
# self.delete_every_recore_on_that_model(models.BusinessImpact)
self.delete_every_record_that_match_criteria(
models.BusinessImpact,
{"client": client, "business_process": business_process},
)
excel_file = pd.read_excel(file))
data = pd.DataFrame(
excel_file,
columns=self.get_excel_fields(
models.BusinessImpact.excel_titles),
)
for _, row in data.iterrows():
self.create_model_object(
models.BusinessImpact,
row,
{"client": client.id, "business_process": business_process.id},
)
return Response("Successfully Loaded data from excel.")
else:
return Response(
{"file": ["File type must be excel with .xlxs extension."]},
status=status.HTTP_400_BAD_REQUEST,
)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
My API is working well but It's not reading all rows instead it reads the last row and returns it. Here is console log of what I get from the API.
0:
asset_categorization: "Sensitive"
asset_name: "Primary Data Center"
asset_risk: "High"
asset_type: "I"
business_assets: "Infrastructure"
business_process: {id: 1, name: 'Credit Management'}
client: 1
cpe: "cpe:2.3:a:oracle:peoplesoft_enterprise:8.22.14"
hierarchy: "L7 / DATA CENTER"
id: 1170
product: "gbfg"
vendors: "ghg"
version: "fgf"
_geolocation: "cvb v"
_regulations: "gvbv"
[[Prototype]]: Object
What can I do to read all rows?
Thanks
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
