Home > database >  Update_or_create method with unique field in Django
Update_or_create method with unique field in Django

Time:06-14

I would like to update or create data in my database by importing a CSV file.

I tested and when I import the CSV file when the "plants" have not already been created it works but when there are the same name of the plants in my database I have an integrity error:

IntegrityError : duplicate key value violates unique constraint "perma_plants_plant_name_key" DETAIL: Key (name)=(Test bis) already exists.

So my update_or_create method does not work because in my model the name field must be unique. How can I do to solve this problem?

Here is my model :

class Plant(models.Model):

    name = models.CharField(max_length=150, unique=True)

    def __str__(self):
        return self.name

Here is my views.py:

class UploadFileView(generics.CreateAPIView):
    serializer_class = FileUploadSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        file = serializer.validated_data['file']
        reader = pd.read_csv(file)
        for _, row in reader.iterrows():
            Plant.objects.update_or_create(
                name=row['Name'],
            )
        return Response({"status": "Success : plants created"},
                        status.HTTP_201_CREATED)

CodePudding user response:

In order to identify the plants, we need a separate field from the name. We could use the default Django "pk" as primary key, but since you want to import it from a CSV, we'll create a "custom_id" on your model:

class Plant(models.Model):
    name = models.CharField(max_length=150, unique=True)
    custom_id = models.CharField(primary_key=True, max_length=20, unique=True)
    def __str__(self):
        return self.name

Before adding the primary key, you will probably have to delete all the plants and empty the database so that it will let you do the migrate.

Now your csv should have two columns, "name" and "custom_id", and the views.py would look like this:

class UploadFileView(generics.CreateAPIView):
    serializer_class = FileUploadSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        file = serializer.validated_data['file']
        reader = pd.read_csv(file)
        for _, row in reader.iterrows():
            Plant.objects.update_or_create(
                custom_id=row['custom_id'],
                defaults={
                    "name":row['Name'],
                    "custom_id": row['custom_id'],
                }
        return Response({"status": "Success : plants created"},
                        status.HTTP_201_CREATED)

With this code, the actual plant identifier is the "custom_id", which should be fixed and never changed once you assign it.You have to respect it every time you import the CSV. And when you add a new plant, you "invent" a new custom_id (which logically cannot be repeated with any other).

  • Related