在Django管理编辑表单中按国家过滤城市

1 投票
2 回答
3416 浏览
提问于 2025-04-18 16:41

我在一个小项目中使用了 django-cities,这个项目是用来列出地点的。

地点的模型是这样的:

class Location(models.Model):
    def __unicode__(self):
        return self.name

    name = models.CharField(max_length=200)
    instagram_id = models.IntegerField(default=0)
    country = models.CharField(max_length=200)
    city = models.CharField(max_length=200)

    new_city = models.ForeignKey(City, related_name='venuecity', null=True, blank=True)

    latitude = models.DecimalField(max_digits=17, decimal_places=14, default=0)
    longitude = models.DecimalField(max_digits=17, decimal_places=14, default=0)

这里的 'city' 和 'new_city' 字段是临时的,我正在迁移数据。

我遇到的问题是在管理后台,如何根据国家来过滤城市选择框?我的目标是让用户在添加新记录或编辑现有记录时,更容易选择正确的城市。

我查阅了 Django 的管理文档,但没能找到解决办法。

2 个回答

0

我试过上面提到的解决办法(@jdl2003),但在Django 1.8中没用,还是遇到了和@bruno-amaral说的一样的错误。我是这样解决这个问题的:

#forms.py
from django.forms import ModelForm, ModelChoiceField
from cities_light.models import City

class MyUserAdminForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyUserAdminForm, self).__init__(*args, **kwargs)
        if self.instance:
            country = self.instance.country
            cities = country.city_set.all() if country else City.objects.none()
            self.fields['city'] = ModelChoiceField(queryset=cities)

#admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from myapp.forms import MyUserAdminForm

class MyUserAdmin(UserAdmin):
    form = MyUserAdminForm
    UserAdmin.fieldsets += (
        (None, {'fields': ('dob', 'country', 'city')}),
    )
    UserAdmin.list_display += ('country',)

admin.site.register(get_user_model(), MyUserAdmin)

现在我唯一的问题是,城市列表没有动态更新。我需要先保存国家字段,然后城市才会更新。

2

你可以自定义Django后台使用的表单。在你的应用里,创建一个符合你需求的表单。在这种情况下,你可能需要写一个重载表单的__init__()方法的表单,以便动态调整城市字段的值。例如:

class LocationAdminForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(LocationAdminForm, self).__init__(*args, **kwargs)
        if self.instance:
            # we're operating on an existing object, not a new one...
            country = self.instance.country
            cities = # get cities from your master countries list...
            self.fields["new_city"] = ChoiceField(choices=cities)

一旦你有了一个可用的ModelForm,你可以在admin.py里告诉后台使用它:

class LocationAdmin(admin.ModelAdmin):
    form = LocationAdminForm

关于后台自定义的详细说明可以在这里找到。还有一篇虽然有点旧但仍然适用的关于动态Django表单的文章在这里

如果你想为新记录做到这一点,你需要在前端实现大部分功能。你需要一些JavaScript代码来动态获取和更新城市列表,当用户选择不同的国家时。你的Django应用需要提供一个AJAX视图,JavaScript可以调用它。这个视图会接收国家信息,并返回一个简单的JSON对象,里面包含城市数据,然后用这些数据更新表单中的元素。

另外,如果你改变一下工作流程,也可以实现一个纯服务器端的解决方案。这可以像一个“向导”一样,首先让用户选择国家。点击下一步后,显示第二步的向导,里面有动态生成的Django表单。你可以参考Django向导应用

撰写回答