Как получить несколько значений из поля модели в поле выбора формы?

У меня есть модель Listing, в которой есть поле categories, хранящее все различные категории. Есть также форма с полем categories, которое должно показывать пользователю поле выбора, где выбор должен быть значениями, хранящимися в поле модели Listing.categories. Я попытался выполнить цикл, но это невозможно, так как значения поля выбора хранятся в формате dict.

Как мне получить значения из поля модели в поле выбора?

models.py

class Category(models.Model):
    name = models.CharField(max_length=50)


class Listing(models.Model):
    ...
    category = models.ForeignKey(Category, on_delete=models.PROTECT, null=True)

forms.py:

from .models import Listing

# example of what I was trying to do

condition_choices = (
    (1, 'New'),
    (2, 'Refurbished'),
    (3, 'Opened'),
    (4, 'Used'),
)

###

for i in Listing.category:
    category_choices = (
        (i, Listing.category)
    )


class NewListing(forms.Form):
    ...
    category = forms.ChoiceField(choices=category_choices)

Вы можете использовать поле ModelChoiceField для того, чтобы передать набор запросов и позволить пользователю выбрать между всеми моделями в этом наборе. Тогда вы получите что-то вроде :

category = forms.ModelChoiceField(queryset=Category.objects.all())

Для себя я сделал это следующим образом:

Модели (поля выбора находятся в ваших моделях)

   CATEGORYCHOICES=(
    (1, 'New'),
    (2, 'Refurbished'),
    (3, 'Opened'),
    (4, 'Used'),
)
    
    class Listing(models.Model):
    ...
    categories = models.IntegerField(choices=CATEGORYCHOICES,default=0)

Затем в файле forms.py вам нужно будет использовать "form select"

class NewListing(ModelForm):
    class Meta:
        model = Listing
        fields = ('field_name1','field_name2')
        
        labels ={
            'field_name1': '',
            'field_name2': '',
        }
        widgets = {
                    'field_name1':forms.Select(attrs={'class':'form-control'}),
                    'field_name2': forms.Select(attrs={'class':'form-control'}),
          }

Имеет ли это смысл?

Вам, очевидно, потребуется обработать эти данные в вашем views.py. Дайте мне знать, если у вас есть вопрос, я буду рад поделиться кодом, который у меня есть для этого.

Если Category является моделью, то ваша condition_choices должна быть избыточной, зачем использовать модель, если эти опции жестко закодированы? Вместо того, чтобы просто использовать forms.Form, вы должны использовать модельную форму forms.ModelForm. Затем вы можете передать выбор категории через queryset:

class ListingForm(forms.ModelForm):
   self.categories = Category.objects.all()
   super(ListingForm, self).__init__(*args, **kwargs)
   self.fields['categories'].queryset = self.categories

Определение класса, как показано здесь, выполняется до инициализации моделей. Таким образом, вы должны сделать что-то динамическое, чтобы сконструировать класс формы или изменить его варианты.

Я только что попробовал это в консоли, и, кажется, это работает. Определите BaseForm со всеми полями, с которыми вы не хотите возиться во время выполнения:

class BaseForm( forms.Form): 
    something = forms.WhateverField( args)
    ...

отключение динамического поля выбора. Во время выполнения, скажем, в методе get_form_class представления на основе класса, создайте нужную вам форму с помощью 3-аргумента type.

Я не очень понимаю, что queryset возвращает набор категорий, поэтому адаптируйте этот код

class SomethingView( FormView): 
    ...
    def get_form_class( self):

    # interrogate the DB to get a list of categories, or categories and labels.

         choices = list( enumerate(categories) ) # [ (0,'cat0'), (1,'cat1'), ...]
         choicefield = forms.ChoiceField( choices=choices, ...)

         return type('My_runtime_form',
             (BaseForm, ),
             { 'category': choicefield }
         ) 

Если бы у вас была таблица DB Categories, содержащая пару значений choice_value и choice_label, то вы могли бы получить варианты как

choices = Category.objects.filter( ... # maybe via a ManyToMany relation
    ).values_list('choice_value', 'choice_label')
Вернуться на верх