Django REST Framework:基于联合唯一约束的存在则更新序列化器
Alright, let's work through this. You've got a Run model with a unique constraint on (start_time, chamber), and you want a Django REST Framework serializer that will update an existing instance if that unique combination already exists, instead of throwing a validation error. Here's a clean way to implement this:
First, let's recap your Run model (plus a basic Chamber model assumption since you referenced it):
from django.db import models class Chamber(models.Model): name = models.CharField(max_length=100, unique=True) # Assuming your Chamber uses a unique name field def __str__(self): return self.name class Run(models.Model): start_time = models.DateTimeField(db_index=True) end_time = models.DateTimeField() chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE) class Meta: unique_together=(('start_time', 'chamber'),)
Now here's the serializer that handles the upsert (update or insert) behavior:
from rest_framework import serializers from .models import Run, Chamber class RunSerializer(serializers.ModelSerializer): # Convert the chamber name from your POST data to a valid Chamber instance chamber = serializers.SlugRelatedField( queryset=Chamber.objects.all(), slug_field='name' # Replace this with your Chamber field that stores values like "My Test Chamber" ) class Meta: model = Run fields = ['start_time', 'end_time', 'chamber'] def create(self, validated_data): # Extract the fields that form your unique constraint unique_identifiers = { 'start_time': validated_data['start_time'], 'chamber': validated_data['chamber'] } # Use Django's get_or_create to fetch existing run or create a new one run, created = Run.objects.get_or_create( **unique_identifiers, defaults=validated_data ) # If the run already exists, update its fields (we'll update end_time here) if not created: # Update specific fields or loop through all validated data if needed run.end_time = validated_data['end_time'] # Add more field updates here if you want to sync other values run.save() return run
How this works:
- SlugRelatedField: This handles converting the chamber name from your POST data ("My Test Chamber") into a valid
Chamberinstance. It also automatically validates that the chamber exists in the database. - get_or_create: This Django ORM method checks for an existing
Runwith thestart_timeandchambercombination. If it exists, it returns the instance; if not, it creates a new one using the provideddefaultsdata. - Update logic: When the instance already exists (
createdis False), we update the necessary fields (in this caseend_time) and save the changes. You can expand this to update other fields by adding morerun.field = validated_data['field']lines, or even loop through all validated data if you want to sync every value.
Testing with your POST example:
Send this JSON request:
{ "start_time": "2018-11-11T12:00:00Z", "end_time": "2018-11-11T12:00:01Z", "chamber": "My Test Chamber" }
- First request: Creates a new
Runinstance with the provided data. - Second request (with a different
end_time): Finds the existingRunand updates itsend_timeto the new value.
Quick notes:
- Ensure your
Chambermodel has a unique field (likename) that matches the value you're sending in the POST request. If you use a different field (like a slug), just update theslug_fieldinSlugRelatedField. - If you're using a view like
CreateAPIView, this serializer works out of the box—no extra changes needed in the view. - For partial updates (like PATCH requests), you can override the
updatemethod similarly, but the above covers the core upsert behavior for POST.
内容的提问来源于stack exchange,提问作者Mormoran
相关产品推荐
相关产品推荐

