Django技术问询:从旧记录创建新记录的可靠方法及ORM技巧优劣
Great questions—let’s break this down clearly, including best practices and potential pitfalls of your current approach.
1. Reliable Method to Create New Records with the Latest Auto-Increment PK
Your current approach of manually incrementing id has a critical flaw: it’s not safe in concurrent environments. If another request creates a new record between the time you fetch last() and call save(), your code will accidentally update that existing record instead of creating a new one.
The correct, reliable way to generate a new record with Django’s auto-incrementing primary key is to reset the primary key to None. This tells Django the object is a new instance, not an existing one, and it will automatically assign the next available auto-increment ID:
# Fetch the existing record dp = SomeModel.objects.filter(type="customer").last() # Reset primary key to mark this as a new instance dp.pk = None # Use dp.id = None if your primary key is explicitly named 'id' # Update the fields you need to change dp.version += 1 # Save creates a new record with the next auto-increment PK dp.save()
This method works for any primary key type (auto-increment integers, UUIDs, etc.) and eliminates race conditions entirely. You don’t have to worry about guessing the next valid ID—Django handles that for you.
2. Is Your ORM Trick More Efficient or Better?
Short answer: No, it’s not better—in fact, it’s risky. Here’s why:
- Data integrity risks: Concurrent writes can lead to accidental updates of existing records (instead of creating new ones), which can corrupt your data without warning.
- Non-portable: If you ever switch your primary key type (e.g., to UUID for distributed systems), manually incrementing
idwill break completely. Thepk=Noneapproach is universally compatible with Django models. - No performance gain: Both approaches involve one database read (fetching the original record) and one write (saving the new instance). There’s no performance difference between them.
That said, your observation about code brevity is spot-on! The pk=None method is just as concise as your trick—you still only need to modify the 1-2 fields you care about, no manual copying of all other fields required. It gives you the same code savings with none of the risks.
A Quick Note on Your Original Trick’s Behavior
When you set dp.id = dp.id + 1 and save:
- If the new
iddoesn’t exist, Django creates a new record (the behavior you want). - If the new
iddoes exist, Django updates that existing record (the dangerous, unintended behavior).
Using pk=None removes this ambiguity—it will always create a new record, no exceptions.
内容的提问来源于stack exchange,提问作者Prabhakar Shanmugam

