How can I convert a QuerySet list to a list or a dataset for the choices field?

After doing some filters and operations, I write the data to the model.

I get the data after processing in the model. Then I unload the data when displaying the form.

There is a field in the form - which is like a choices field. But I’m not quite sure about the correct spelling for the form.

My problem is that I can display the data for the choices field only after some processing or as a result of receiving data from another model.

My task is to unload data from another model into the code. And then from the code send it to the choices field. How can I do something similar?

models.py

class Category_pk_for_form_maim (models.Model):
    categoty_name = models.CharField()
    def __str__(self):
        return self.categoty_name
    

class Category_pk_for_form_category (models.Model):
    name_object = models.IntegerField(verbose_name="Наименование объекта")
    category_name = models.CharField()

 
class CreateNewGPR (models.Model):
    name_object = models.IntegerField(verbose_name="Наименование объекта")
    name_category = models.CharField(verbose_name="Наименование категории/раздела/вида работ")
    name_working = models.CharField(verbose_name="Наименование работы")
    type_izm = models.CharField(choices=TYPE_IZMERENIYA, verbose_name="Единицы измерения")
    value_work = models.FloatField(verbose_name="Объём работ")
    lyudi_norma = models.IntegerField(verbose_name="Нормативные затраты персонала")
    technik_norma = models.IntegerField(verbose_name="Нормативные затраты техники")
    date_begin = models.DateField(verbose_name="Дата начала работ")
    date_end = models.DateField(verbose_name="Дата окончания работ")


class GPRWorkingName (models.Model):
    name_working = models.CharField(verbose_name="Наименование работы по ГПР")  
    def __str__(self):
        return self.name_working   

forms.py

class Form_GPR (forms.ModelForm):
    class Meta:
        model = CreateNewGPR
        fields = "name_category", "name_working", "type_izm", "value_work", "lyudi_norma", "technik_norma", "date_begin", "date_end"
        widgets = {
            "name_category": forms.RadioSelect(attrs={"type":"radio"}),
            "date_begin": forms.DateInput(attrs={"class":"form-control", "type":"date"}),
            "date_end": forms.DateInput(attrs={"class":"form-control", "type":"date"}),
            
        }

views.py

def book(request, pk):

    context = {}

    Category_pk_for_form_maim.objects.all().delete()

    filter_qs_category = Category_pk_for_form_category.objects.filter(name_object=pk)
    filter_qs_category = filter_qs_category.values("category_name")

    for item in filter_qs_category:
        entry = item
        new_entry = Category_pk_for_form_maim(categoty_name=entry)
        new_entry.save()

    form_category_1 = Category_pk_for_form_category_Form()
    form_2 = Form_GPR()

    choises_1 = Category_pk_for_form_maim.objects.all()
    choises_1 = choises_1.values_list("categoty_name", flat=True)

    choises_1 = choises_1.values()

    print(choises_1)


    form_2.fields["name_category"].choices = choises_1

    if request.method == 'POST':

        if request.POST.get("form_type") == "form1":
            form_category_1 = Category_pk_for_form_category_Form(request.POST) 
            if form_category_1.is_valid():
                model_instance = form_category_1.save(commit=False)
                name_object = pk
                category_name = model_instance.category_name
                new_entry = Category_pk_for_form_category(name_object=name_object, category_name=category_name)
                new_entry.save()
                return redirect("book-detail", pk)            
        elif request.POST.get("form_type") == "form2":
            form_2 = Form_GPR(request.POST) 
            if form_2.is_valid():
                model_instance = form_2.save(commit=False)
                name_object = pk
                name_working = model_instance.name_working
                type_izm = model_instance.type_izm
                value_work = model_instance.value_work
                lyudi_norma = model_instance.lyudi_norma
                technik_norma = model_instance.technik_norma
                date_begin = model_instance.date_begin
                date_end = model_instance.date_end
                new_entry = CreateNewGPR(name_object=name_object, name_working=name_working, type_izm=type_izm, value_work=value_work, lyudi_norma=lyudi_norma, technik_norma=technik_norma, date_begin=date_begin, date_end=date_end)
                new_entry.save()
                return redirect("book-detail", pk)

    context['form_category_1'] = form_category_1
    context['form_2'] = form_2

    """ Gets an individual book object from the database, based on its ID/PK. Renders a detail template """
    book = get_object_or_404(ArkiObject_1, pk=pk)

    filter_qs = CreateNewGPR.objects.filter(name_object=pk)
    filter_qs = filter_qs.values("name_working", "type_izm", "value_work", "lyudi_norma", "technik_norma", "date_begin", "date_end")

    context['books'] = filter_qs
    return render(request, 'bookdetail.html', context)

What I think you’re asking here is how to dynamically create the choices for a Django forms ChoiceField.

If so, then Django provides that facility directly - see the choices attribute. One of the options is to pass it a callable, which means you can define a function to create the choices options and use that function name in your field definition.

You might also want to read the thread at Passing an altered queryset to ModelChoiceField along with the threads that it links to in the 4th post of that thread.

Thanks Ken, that makes sense.

Just to add, if you’re setting choices from a queryset, you need to turn it into a list of tuples like this:

python

CopyEdit

choices_1 = [(item['category_name'], item['category_name']) for item in filter_qs_category]
form_2.fields['name_category'].choices = choices_1

Using .values() gives you dictionaries, but choices need to be in (value, label) format. This worked for me.

You can also use the values_list method to return a list instead of creating it manually.