django-simple-history重复存储变更记录及clean_duplicate_history命令疑问
django-simple-history重复记录问题解析 & clean_duplicate_history命令说明
Hey there! Let's break down why you're seeing two duplicate history entries on every create/update, and explain what that clean_duplicate_history command is all about.
Why are you getting duplicate history records?
Since you're using CBVs and ModelForms, the most common culprits are:
- Accidentally calling
form.save()twice: In CBVs likeCreateVieworUpdateView, if you manually callform.save()in yourform_validmethod and then let the parent class'sform_validrun (which also callssave()), you'll trigger two history entries. For example:# ❌ Bad: Triggers two saves def form_valid(self, form): form.save() # First history entry return super().form_valid(form) # Parent method calls save() again # ✅ Good: Pick one approach def form_valid(self, form): instance = form.save() # Add your custom logic here return redirect('your-success-url') - Duplicate signal triggers: django-simple-history relies on Django's
post_savesignals to track changes. If your model or a third-party library is registering the history signal multiple times, or ifpost_saveis firing twice for some reason (like nested transactions), you'll get duplicate records. - Version compatibility bugs: Some older versions of django-simple-history had bugs that caused duplicate entries when paired with specific Django versions. Upgrading to the latest stable release often fixes this.
- Transaction edge cases: If your operations are wrapped in
atomicblocks, certain scenarios (like nested transactions or rollback/retries) can lead to duplicate signal fires.
What's the purpose of clean_duplicate_history?
This command is an official cleanup tool built specifically for scenarios like yours:
- It scans all your history models to find duplicate entries—specifically, records that belong to the same parent instance, have the same change type (create/update), and were created at the exact same timestamp (or within a very narrow window, depending on the version).
- It keeps one copy of each duplicate set and deletes the rest, cleaning up the redundant history data that's cluttering your database.
- The command exists because the maintainers recognized that in complex Django setups (like CBVs with custom form logic, or third-party integrations), accidental duplicate triggers can happen, and users need an easy way to fix it without writing custom cleanup queries.
How to prevent duplicates in the future?
Here are a few actionable fixes:
- Audit your CBV
form_validmethods to ensure you're only callingform.save()once per request. - Check if your model's history signal is being registered multiple times (you can debug this by printing Django's registered signals).
- Upgrade django-simple-history to the latest version—check the release notes to see if duplicate entry bugs have been patched for your Django version.
- Avoid unnecessary nested transactions or multiple save calls within atomic blocks.
内容的提问来源于stack exchange,提问作者cwhisperer
相关产品推荐
相关产品推荐

