Django自定义自增主键遇UUID验证错误及数据丢失问题求助
Let's walk through what's going wrong here and fix it step by step:
First Issue: UUID Validation Failed
You defined id as a UUIDField, but your get_next() function returns plain integers like 1, 2, 3. UUID fields require values in a specific UUID format (e.g., 550e8400-e29b-41d4-a716-446655440000), not regular numbers. That's exactly why you hit the ValidationError: "'1' is not a valid UUID." — Django was expecting a UUID but got an integer instead.
Second Issue: Duplicate IDs Breaking Bulk Saves
When you switched to IntegerField, the default=get_next parameter only runs get_next() once when you start creating multiple objects (like in a bulk operation). So every user in your batch ends up with the same ID (e.g., 1). Since primary keys have to be unique, only the first user gets saved, and the rest fail silently (or trigger a database unique constraint error under the hood).
Fix 1: Use Django's Built-in Auto-Increment Key (The Easiest Solution)
Django automatically adds an auto-incrementing integer primary key (id) to every model by default — you don't need to define it manually at all. This handles all the auto-increment logic, including bulk saves, perfectly out of the box.
Your simplified model would look like this:
from django.db import models class Users(models.Model): sex = models.CharField(max_length=100, null=True, default=None) age = models.CharField(max_length=100, null=True, default=None)
Now whenever you create users (even in bulk), Django will automatically assign unique, incrementing IDs to each one without any extra code.
Fix 2: Custom Auto-Increment Logic (If You Need It)
If you have specific requirements that force you to handle ID increments manually (like starting from a non-1 value, or custom gaps), you need to fix the "one-time default call" problem and handle concurrent requests to avoid duplicate IDs.
Here's a robust implementation:
from django.db import models, transaction class Users(models.Model): id = models.IntegerField(primary_key=True, editable=False) sex = models.CharField(max_length=100, null=True, default=None) age = models.CharField(max_length=100, null=True, default=None) @classmethod def get_next_id(cls): # Use an atomic transaction + row lock to prevent race conditions with transaction.atomic(): # Lock the latest user row so no other request can grab the same ID latest_user = cls.objects.order_by('-id').select_for_update().first() return latest_user.id + 1 if latest_user else 1 def save(self, *args, **kwargs): # Only set the ID if this is a new object if not self.id: self.id = self.get_next_id() super().save(*args, **kwargs)
For Bulk Creation:
Since bulk_create skips calling the save() method on each instance, you'll need to pre-generate unique IDs before inserting:
# Example: Create 5 users in bulk start_id = Users.get_next_id() users_batch = [ Users(id=start_id + i, sex="male", age="25") for i in range(5) ] Users.objects.bulk_create(users_batch)
The select_for_update ensures that even if multiple requests try to create users at the same time, they won't end up with duplicate IDs (the database locks the row until the transaction finishes).
内容的提问来源于stack exchange,提问作者user9341676

