在ModelChoiceField-Django中添加多个标签

在ModelChoiceField-Django中添加多个标签,django,django-forms,Django,Django Forms,我有这样的模型: class Cities(models.Model): country = models.CharField(max_length=45, blank=True, null=True) city = models.CharField(max_length=45, blank=True, null=True) def get_city_name(self): if self.sub_species: return

我有这样的模型:

class Cities(models.Model):
    country = models.CharField(max_length=45, blank=True, null=True)
    city = models.CharField(max_length=45, blank=True, null=True)

    def get_city_name(self):
        if self.sub_species:
            return str(self.country) + " " + str(self.city)
使用我的模型中的示例数据:

France Paris
France Lyon
France Marseille
Germany Berlin
Germany Bonn
views.py forms.py 在“我的模板”“我的选择”字段中,呈现前面列出的城市列表

但我想要这样的选择:

France
France Paris
France Lyon
France Marseille
Germany
Germany Berlin
Germany Bonn

用户也可以选择一个国家(在我可以选择城市之后)

您可以对
modelcoocefield.iterator
进行一些神奇的更改,但是此属性没有文档记录,使用风险自负

否则,我认为您需要编写一个自定义的
ChoiceField

class ModelChoiceIterator(forms.models.ModelChoiceIterator):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.seen = set()

    def __iter__(self):
        for id, label in super().__iter__():
            country = label.split(' ')[0]

            if country not in self.seen:
                yield (id, country)
                self.seen.add(country)

            yield (id, label)


class CityNameChoiceField(forms.ModelChoiceField):
    iterator = ModelChoiceIterator

    def label_from_instance(self, obj):
        return obj.get_city_name()

有一种更简单的方法可以实现你想要的东西,只需按照以下步骤组织选择。祝你好运:)


添加您的模板代码。我非常惊讶。这是我想做的。完美答案!如果没有重写
类modelcooceiterator
,我认为不需要编写新的
选择字段。
France
France Paris
France Lyon
France Marseille
Germany
Germany Berlin
Germany Bonn
class ModelChoiceIterator(forms.models.ModelChoiceIterator):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.seen = set()

    def __iter__(self):
        for id, label in super().__iter__():
            country = label.split(' ')[0]

            if country not in self.seen:
                yield (id, country)
                self.seen.add(country)

            yield (id, label)


class CityNameChoiceField(forms.ModelChoiceField):
    iterator = ModelChoiceIterator

    def label_from_instance(self, obj):
        return obj.get_city_name()
def cities_as_choices():
    choices = []
    for country in models.Cities.objects.values('country').distinct():
        new_country = []
        cities = []
        new_country.append(country.get('country'))

        for city in models.Cities.objects.filter(country=country.get('country')):
            cities.append([city.pk, city.city])

        new_country.append(cities)
        choices.append(new_country)

    return choices


class CityNameForm(forms.Form):
    """
    CityNameForm Class
    """

    def __init__(self, *args, **kwargs):
        super(CityNameForm, self).__init__(*args, **kwargs)
        self.fields['cityName'].choices = cities_as_choices()

    cityName = forms.ChoiceField(
        choices=cities_as_choices(),
        help_text="",
        required=False,
        label='Cities',
    )