【问题标题】:Filtering cities by country in the django admin edit form在 django 管理编辑表单中按国家/地区过滤城市
【发布时间】:2014-08-09 21:51:03
【问题描述】:

我在一个列出位置的小项目中使用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)

“城市”和“新城市”字段在我迁移数据时是临时的。

我的问题出在管理方面,如何按国家/地区过滤城市选择字段?目的是让用户在添加新记录或编辑现有记录时更容易选择正确的城市。

我查看了 django 的管理文档,但不知道该怎么做。

【问题讨论】:

  • 您是否考虑过创建自定义列表过滤器?
  • 有一种方法可以通过name 或任何其他字段列出管理面板中的所有条目。我认为从这一点开始会有所帮助。
  • 对不起,我现在意识到我并不清楚。问题是当我编辑一个位置时,选择字段将显示世界上所有的城市。理想情况下,会有两个选择字段:一个用于国家/地区,另一个用于城市。

标签: python django admin


【解决方案1】:

您可以自定义 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

管理员自定义记录在here。一篇关于动态 Django 表单的旧但仍然最相关的文章是 here

要为新记录执行此操作,您需要在前端实现大部分内容。您将需要 Javascript 代码在选择不同的国家/地区时动态检索和更新城市列表。您的 Django 应用程序将公开 Javascript 可以调用的 AJAX 视图。它将传递国家并返回一个简单的城市 JSON 对象,它将用于更新表单中的元素。

或者,如果您更改工作流程,则可以使用纯服务器端解决方案。这可以像“向导”一样工作,并要求用户首先选择国家。单击下一步以查看向导的第 2 步,其中包含如上动态生成的 Django 表单。 Django wizard app 可能有用。

【讨论】:

  • 谢谢@jdl2003,这是一个巨大的帮助。刚刚在 ChoiceField 中遇到了一个小障碍。我收到错误“无法分配“u'2509408'”:“Location.new_city”必须是“City”实例。”当我尝试更新它时。至于新的记录案例,前端解决方案似乎更好。我也在使用 autocomplete-light 应用程序,它可以让用户更轻松。
  • 听起来 ChoiceField 需要 City 对象,而您给它的是 unicode 字符串。您如何在 init 中构建城市列表?也许试试:City.objects.filter(country__code=self.instance.country)。
  • 当我这样做时,我收到一个错误,即 City 对象不可迭代。所以我在做 city = City.objects.filter(country__name=self.instance.country).values_list('id', 'name')
【解决方案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)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-27
    • 2011-04-28
    • 2017-06-30
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多