Задать вопрос
@TitanFighter

ModelChoiceField\label_from_instance или как сделать Choices используя данные 2х моделей для вывода стран в профиле пользователя?

Доброго времени суток

Хочу пользователю дать возможность выбирать свою страну. В одной модели имеются данные по странам, в другой переводы стран. Сделал через ModelChoiceField с переопределением label_from_instance, но проблема в том, что из-за этого самого label_from_instance растет к-во запросов и страница долго грузится. Подскажите, как ускорить\реализовать решение иным образом?

# admindivisions.models
class Countries(models.Model):
    osm_id = models.IntegerField(db_index=True, null=True)
    status = models.IntegerField()
    population = models.IntegerField(null=True)
    iso3166_1 = models.CharField(max_length=2, blank=True)
    iso3166_1_a2 = models.CharField(max_length=2, blank=True)
    iso3166_1_a3 = models.CharField(max_length=3, blank=True)
    class Meta:
        db_table = 'admindivisions_countries'
        verbose_name = 'Country'
        verbose_name_plural = 'Countries'

class CountriesTranslations(models.Model):
    common_name = models.CharField(max_length=81, blank=True, db_index=True)
    formal_name = models.CharField(max_length=100, blank=True)
    country = models.ForeignKey(Countries, on_delete=models.CASCADE, verbose_name='Details of Country')
    lang_group = models.ForeignKey(LanguagesGroups, on_delete=models.CASCADE, verbose_name='Language of Country',
                                   null=True)
    class Meta:
        db_table = 'admindivisions_countries_translations'
        verbose_name = 'Country Translation'
        verbose_name_plural = 'Countries Translations'

 # profiles.forms
class CountriesChoiceField(forms.ModelChoiceField):
    def __init__(self, user_lang='en', *args, **kwargs):
        super(CountriesChoiceField, self).__init__(*args, **kwargs)
        self.user_lang = user_lang
    def label_from_instance(self, obj):
        return obj.countriestranslations_set.get(lang_group=self.user_lang)

class UserProfileForm(forms.ModelForm):
user_lang = user_lang_here
country = CountriesChoiceField(
    queryset=Countries.objects.filter(
        status=1, iso3166_1__isnull=False,
        countriestranslations__lang_group=user_lang).order_by('countriestranslations__common_name'),
    widget=forms.Select(), user_lang=user_lang)
    class Meta:
        model = UserProfile()
        fields = ('email', 'email_privacy',
                  'profile_url',
                  'first_name', 'last_name',
                  'country',)


Пробовал использовать ChoiceField через генерацию tuple
# profiles.forms
class UserProfileForm(forms.ModelForm):
    # PREPARE CHOICES
    country_choices = ()
    lang_group = Languages.objects.get(iso_code='en').group
    for country in Countries.objects.filter(status=1):
        eng_name = country.countriestranslations_set.filter(lang_group=lang_group).first()
        if eng_name:
            country_choices += ((country, eng_name.common_name),)
    country_choices = sorted(country_choices, key=lambda tup: tup[1])
    country = forms.ChoiceField(choices=country_choices, required=False)
    class Meta:
        model = UserProfile()
        fields = ('email', 'email_privacy',
                  'profile_url',
                  'first_name', 'last_name',
                  'country',)
# profiles.views
def profile_settings(request):
    if request.method == 'POST':
        user_profile_form = UserProfileForm(request.POST, instance=request.user)
        if user_profile_form.is_valid():
            user_profile_form.save()
            messages.success(request, _('Your profile was successfully updated!'))
            return redirect('settings')
        else:
            messages.error(request, _('Please correct the error below.'))
    else:
        user_profile_form = UserProfileForm(instance=request.user)
    return render(request, 'profiles/profiles_settings.html', {
        'user_profile_form': user_profile_form,
    })

Но возникает Exception Value: Cannot assign “'AF'”: “UserProfile.country” must be a “Countries” instance. на строке if user_profile_form.is_valid():

Благодарю.
  • Вопрос задан
  • 484 просмотра
Подписаться 1 Оценить Комментировать
Решения вопроса 1
@TitanFighter Автор вопроса
Решение проблемы

class CountriesChoiceField(forms.ModelChoiceField):
    def __init__(self, user_lang, *args, **kwargs):
        queryset = Countries.objects.filter(
            status=1, iso3166_1__isnull=False,
            countriestranslations__lang_group=user_lang).order_by('countriestranslations__common_name')

        super(CountriesChoiceField, self).__init__(queryset, *args, **kwargs)

        self.translations = OrderedDict()
        for country in queryset:
            name = country.countriestranslations_set.get(lang_group=user_lang).common_name
            self.translations[country] = name

    def label_from_instance(self, obj):
        return self.translations[obj]

class UserProfileForm(forms.ModelForm):
    user_lang = user_lang_here
    country = CountriesChoiceField(widget=forms.Select(), user_lang=user_lang)

    class Meta:
        model = UserProfile()
        fields = ('email', 'email_privacy',
                  'profile_url',
                  'first_name', 'last_name',
                  'country',)

В итоге имеем 7 queries in 29.45ms против 73 queries in 92.52ms
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
Strikt Москва
от 100 000 до 180 000 ₽
ITK academy Саратов
от 75 000 ₽
Sim-Ba Pay Санкт-Петербург
от 180 000 ₽