Django Admin:实现禁止删除食谱最后食材或删除食材时删除食谱
解决Django Admin食谱食材关联的两种逻辑实现
问题背景
需要实现以下两种逻辑之一:
- 禁止删除食谱的最后一个食材,避免食谱变为无食材状态;
- 删除最后一个食材时自动删除对应的食谱。
此前尝试在IngredientRecipeInline中设置min_num=1但未生效,原因是Django Admin的min_num仅在创建新对象时强制验证,编辑已有对象时不会阻止删除所有关联行。
方案一:禁止删除最后一个食材
通过重写Inline的formset验证逻辑,在保存时检查剩余食材数量:
from django import forms class IngredientRecipeInline(admin.TabularInline): model = IngredientRecipe min_num = 1 def get_formset(self, request, obj=None, **kwargs): formset = super().get_formset(request, obj, **kwargs) def clean_formset(): cleaned_data = formset.cleaned_data # 筛选出未被删除且非空的食材行 active_ingredients = [ data for data in cleaned_data if not data.get('DELETE', False) and data ] # 仅对已有食谱进行验证(新建食谱时min_num已生效) if obj and len(active_ingredients) == 0: raise forms.ValidationError("食谱必须至少保留一个食材") return cleaned_data formset.clean = clean_formset return formset
当尝试删除最后一个食材并保存时,Admin会抛出验证错误,阻止操作。
方案二:删除最后一个食材时自动删除食谱
利用Django的post_delete信号,在食材关联记录删除后检查食谱的剩余食材数量,若为0则删除食谱:
在模型文件中添加信号处理:
from django.db.models.signals import post_delete from django.dispatch import receiver @receiver(post_delete, sender=IngredientRecipe) def auto_delete_recipe_on_last_ingredient(sender, instance, **kwargs): # 统计该食谱剩余的食材关联记录数 remaining_count = instance.recipe.ingredientrecipe_set.count() if remaining_count == 0: instance.recipe.delete() # 注册信号(若使用Django 3.2+,装饰器已自动完成注册,此句可省略) post_delete.connect(auto_delete_recipe_on_last_ingredient, sender=IngredientRecipe)
若项目使用AppConfig,需确保信号在App启动时加载,可在apps.py的ready()方法中导入信号模块:
from django.apps import AppConfig class RecipesConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'recipes' def ready(self): import recipes.signals # 假设信号单独放在signals.py文件中
内容的提问来源于stack exchange,提问作者vhskonami
相关产品推荐
相关产品推荐

