0

I need to import data from a CSV file which contains monthly-bill, the CSV contains customer information but instead of creating one model I extracted the customer-related information onto a different model named Customer. Also, the monthly-bill model should have a foreign key of an organization that is not part of the CSV.

Sample CSV format
customer_name | address | account_number | total_bill | date

I tried overriding the before_import and before_import_row but it seems that it doesn't add the row (or maybe I'm missing something)

I think I got it to work, currently checking how to manage the ID because the CSV doesn't contain the ID it is generated and in UUID format.

UPDATE:

I'm confused, if I add account_number as import_id_fields the error returns, it doesn't add the customer_id and organization_id. I've read the documentation and it states that before_import_row is where we add additional logic but when I say it is not working is because regardless of what I added I still get errors stating that customer_id is null and violates the null constraint. Also tried adding the "id" column since my IDs are auto-generated still no luck.

Here is the snippet of my resource

class WaterBillRecordResource(resources.ModelResource):
    bill_date = fields.Field(attribute="bill_date", widget=widgets.DateWidget())
    service_rate = fields.Field(attribute="service_rate", widget=widgets.DecimalWidget())
    total_consumed = fields.Field(attribute="total_consumed", widget=widgets.DecimalWidget())
    total_billing = fields.Field(attribute="total_billing", widget=widgets.DecimalWidget())

    class Meta:
        model = WaterBillRecord
        skip_unchanged = True
        report_skipped = False
        import_id_fields = ('id',)
        fields = (
            "bill_date",
            "account_number",
            "service_rate",
            "total_consumed",
            "total_billing",
            "account_status",
            "customer_id"
            "organization_id"
        )
        export_order = (
            "account_number",
            "account_status",
            "service_rate",
            "total_consumed",
            "total_billing",
            "bill_date",
        )

    def before_import(self, dataset, using_transactions, dry_run, **kwargs):
        dataset.insert_col(0, col=["", ] * dataset.height, header="id")

    def get_instance(self, instance_loader, row):
        return False

    def before_import_row(self, row, row_number=None, **kwargs):
        organization = Organization.objects.get(slug="jba")
        account_number = row.get("account_number")
        name = row.get("customer_name")
        address_line_1 = row.get("address_line_1")
        address_line_2 = row.get("address_line_2")
        city = row.get("city")
        state = row.get("state")
        zip_code = row.get("zip")
        property_size = row.get("lot_size")

        customer, created = Customer.objects.get_or_create(
            name=name,
            account_number=account_number,
            defaults={
                "name": name,
                "organization": organization,
                "account_number": account_number,
                "address_line_1": address_line_1,
                "address_line_2": address_line_2,
                "city": city,
                "state": state,
                "zip_code": zip_code,
                "property_size": property_size
            }
        )
        row["organization_id"] = organization.id
        row["customer_id"] = customer.id
n0minal
  • 3,195
  • 9
  • 46
  • 71
  • Your question isn't very clear, but I think you are importing an instance of a Customer which needs to have preset values. If so, please take a look at [this answer](https://stackoverflow.com/a/68115495/39296). You need to create a Customer resource but pass in the non-csv values at runtime (e.g. 'organization_id'). If I've got this wrong, please clarify the question and I will try to help. – Matthew Hegarty Jul 04 '21 at 17:28
  • Sorry, but basically I need to import a CSV but instead of it all in one model I need to extract the customer-related data onto a separate model but I need to do a get_or_create so that it will not create the same customer record every time a CSV gets uploaded. Also, the monthly_bill and customer model both have an organization as foreign_key which should be coming from the request.user but I'll figure that out later on. – n0minal Jul 05 '21 at 07:22
  • I suggest use `before_import_row()` to create the Customer if it doesn't exist - you say you've tried this though - can you update your question to clarify what is not working – Matthew Hegarty Jul 05 '21 at 13:12
  • I updated it but I think I got it working I was missing the fields but now my problem is the ID since I have UUID generated ids. – n0minal Jul 05 '21 at 14:04

1 Answers1

0

I have able to fix it by doing this. I had to read the documentation multiple times so basically, I specified a custom field and specified the attribute name so that it matches the key I added to before_import_row

class WaterBillRecordResource(resources.ModelResource):
    bill_date = fields.Field(attribute="bill_date", column_name="date", widget=widgets.DateWidget())
    organization_id = fields.Field(attribute="organization_id")
    customer_id = fields.Field(attribute="customer_id")

    class Meta:
        model = WaterBillRecord
        exclude = ("id",)
        import_id_fields = ('account_number',)
        fields = (
            "bill_date",
            "account_number",
            "service_rate",
            "total_consumed",
            "total_billing",
            "account_status",
            "customer_id"
            "organization_id"
        )

    def get_instance(self, instance_loader, row):
        return False

    def before_import_row(self, row, row_number=None, **kwargs):
        organization = Organization.objects.get(slug="jba")
        account_number = row.get("account_number")
        name = row.get("customer_name")
        address_line_1 = row.get("address_line_1")
        address_line_2 = row.get("address_line_2")
        city = row.get("city")
        state = row.get("state")
        zip_code = row.get("zip")
        property_size = row.get("lot_size")

        customer, created = Customer.objects.get_or_create(
            name=name,
            account_number=account_number,
            defaults={
                "name": name,
                "organization": organization,
                "account_number": account_number,
                "address_line_1": address_line_1,
                "address_line_2": address_line_2,
                "city": city,
                "state": state,
                "zip_code": zip_code,
                "property_size": property_size
            }
        )
        row["organization_id"] = organization.id
        row["customer_id"] = customer.id
n0minal
  • 3,195
  • 9
  • 46
  • 71