Django Admin:排除下拉旧FoR代码且保留已有值
问题
我运营一个会议排名网站,FoR代码是其中一个字段。数据库里存有已停用的旧FoR代码,我想在Admin修改表单的下拉菜单里排除这些旧代码——因为滚动查找当前有效代码太麻烦(原问题附下拉菜单过长的截图)。
我尝试重写formfield_for_foreignkey方法排除旧代码,但打开带有旧代码的会议条目时,FoR代码的下拉框被清空了(原问题附下拉框为空的截图)。
请问能不能在排除旧FoR代码的同时,保留旧条目中的FoR代码?比如示例里,我想保留旧条目的0905代码,仅给新条目显示当前有效的代码。
现有代码
admin.py
class RankInline(admin.TabularInline): model = Rank extra = 1 def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "for": kwargs["queryset"] = ForCode.objects.filter(code__startswith="46") return super(RankInline, self).formfield_for_foreignkey(db_field, request, **kwargs) class CommentInLine(admin.TabularInline): model = Comment extra = 0 class ConferenceAdmin(admin.ModelAdmin): list_display = ("acronym", "title", "url") list_display_links = ("acronym", "title", "url") search_fields = ("acronym", "title", "url") inlines = (RankInline, CommentInLine)
models.py
class ForCode(models.Model): code = models.CharField(max_length=6, primary_key=True) name = models.TextField() source = models.ForeignKey(Source, on_delete=models.CASCADE) class Rank(models.Model): conference = models.ForeignKey(Conference, on_delete=models.CASCADE) source = models.ForeignKey(Source, on_delete=models.CASCADE) rank = models.CharField(max_length=255) for_code = models.ForeignKey(ForCode, db_column="for", null=True, blank=True, on_delete=models.SET_NULL)
解决方案
问题出在你当前的formfield_for_foreignkey只过滤出了以46开头的FoR代码,而旧条目关联的0905不在这个集合里,所以编辑旧条目时下拉框就空了。要实现“旧条目保留原有代码,新条目只显示有效代码”的需求,可以修改formfield_for_foreignkey方法,在过滤有效代码的基础上,把当前对象已关联的旧代码也加入到查询集里:
修改后的RankInline代码如下:
class RankInline(admin.TabularInline): model = Rank extra = 1 def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "for": # 先获取当前有效的FoR代码(以46开头) valid_for_codes = ForCode.objects.filter(code__startswith="46") # 如果是编辑已有Rank对象,把它关联的FoR代码也加入查询集 if self.instance.pk: current_for_code = self.instance.for_code if current_for_code: # 合并有效代码和当前代码,去重 valid_for_codes = valid_for_codes | ForCode.objects.filter(pk=current_for_code.pk) kwargs["queryset"] = valid_for_codes.order_by('code') return super(RankInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
逻辑说明
- 首先筛选出所有有效的FoR代码(以46开头);
- 通过
self.instance.pk判断是否为编辑模式:存在则说明是修改已有条目; - 如果是编辑模式,获取当前条目关联的FoR代码,将其加入到有效代码的查询集中;
- 把合并后的查询集赋值给
kwargs["queryset"],并按code排序方便查找。
这样处理后:
- 编辑旧条目时,下拉框会显示原有旧代码+所有有效代码;
- 添加新条目时,下拉框只显示有效代码。
内容的提问来源于stack exchange,提问作者JAK Zero
相关产品推荐
相关产品推荐

