在Django管理编辑表单中按国家过滤城市
我在一个小项目中使用了 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 个回答
我试过上面提到的解决办法(@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)
现在我唯一的问题是,城市列表没有动态更新。我需要先保存国家字段,然后城市才会更新。
你可以自定义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向导应用。