You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

逻辑说明

  1. 首先筛选出所有有效的FoR代码(以46开头);
  2. 通过self.instance.pk判断是否为编辑模式:存在则说明是修改已有条目;
  3. 如果是编辑模式,获取当前条目关联的FoR代码,将其加入到有效代码的查询集中;
  4. 把合并后的查询集赋值给kwargs["queryset"],并按code排序方便查找。

这样处理后:

  • 编辑旧条目时,下拉框会显示原有旧代码+所有有效代码;
  • 添加新条目时,下拉框只显示有效代码。

内容的提问来源于stack exchange,提问作者JAK Zero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 13:05:12