Performs an upsert with the set of models defined in rows. If the unique field which is meant
        to cause a conflict is an auto increment field, then the field should be excluded when its value is null.
        In this case, an upsert will be performed followed by a bulk_create

def upsert(self, rows, unique_fields, update_fields, return_rows=False, return_models=False):
        """
        Performs an upsert with the set of models defined in rows. If the unique field which is meant
        to cause a conflict is an auto increment field, then the field should be excluded when its value is null.
        In this case, an upsert will be performed followed by a bulk_create
        """
        if len(rows) == 0:
            return

        ModelClass = self.tables[0].model

        rows_with_null_auto_field_value = []

        # Get auto field name (a model can only have one AutoField)
        auto_field_name = self.get_auto_field_name(ModelClass)

        # Check if unique fields list contains an auto field
        if auto_field_name in unique_fields:
            # Separate the rows that need to be inserted vs the rows that need to be upserted
            rows_with_null_auto_field_value = [row for row in rows if getattr(row, auto_field_name) is None]
            rows = [row for row in rows if getattr(row, auto_field_name) is not None]

        return_value = []

        if rows:
            sql, sql_args = self.get_upsert_sql(
                rows,
                unique_fields,
                update_fields,
                auto_field_name=auto_field_name,
                return_rows=return_rows or return_models
            )

            # get the cursor to execute the query
            cursor = self.get_cursor()

            # execute the upsert query
            cursor.execute(sql, sql_args)

            if return_rows or return_models:
                return_value.extend(self._fetch_all_as_dict(cursor))

        if rows_with_null_auto_field_value:
            sql, sql_args = self.get_upsert_sql(
                rows_with_null_auto_field_value,
                unique_fields,
                update_fields,
                auto_field_name=auto_field_name,
                only_insert=True,
                return_rows=return_rows or return_models
            )

            # get the cursor to execute the query
            cursor = self.get_cursor()

            # execute the upsert query
            cursor.execute(sql, sql_args)

            if return_rows or return_models:
                return_value.extend(self._fetch_all_as_dict(cursor))

        if return_models:
            ModelClass = self.tables[0].model
            model_objects = [
                ModelClass(**row_dict)
                for row_dict in return_value
            ]

            # Set the state to indicate the object has been loaded from db
            for model_object in model_objects:
                model_object._state.adding = False
                model_object._state.db = 'default'

            return_value = model_objects

        return return_value