How to choose the value and label from Django ModelChoiceField queryset

Question:

I was trying to create a django form and one of my field contain a ModelChoiceField

class FooForm(forms.Form):

    person =  forms.ModelChoiceField(queryset=Person.objects.filter(is_active=True).order_by('id'), required=False)
    age = forms.IntegerField(min_value=18, max_value=99, required=False)

When I try the code above what it return as an html ouput is

<option value="1">Person object</option>

on my Person Model I have the fields “id, fname, lname, is_active” . Is it possible to specify that my dropdown option will use “id” as the value and “lname” as the label? The expected html
should be

<option value="1">My Last Name</option>

Thanks in advance!

Asked By: helloworld2013

||

Answers:

From the Django docs:

https://docs.djangoproject.com/en/dev/ref/forms/fields/#django.forms.ModelChoiceField

The __unicode__ (__str__ on Python 3) method of the model will be
called to generate string representations of the objects for use in
the field’s choices; to provide customized representations, subclass
ModelChoiceField and override label_from_instance. This method will
receive a model object, and should return a string suitable for
representing it. For example:

from django.forms import ModelChoiceField

class MyModelChoiceField(ModelChoiceField):
    def label_from_instance(self, obj):
        return "My Object #%i" % obj.id

So, you can do that, or override __str__ on your model class to return the last name.

Answered By: FogleBird

In your Person model add:

def __unicode__(self):
    return u'{0}'.format(self.lname)

If you are using Python 3, then define __str__ instead of __unicode__.

def __str__(self):
    return u'{0}'.format(self.lname)
Answered By: danielcorreia

You can just add a call to label_from_instance in the init of Form ie

by adding something like

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

        self.fields['field_name'].label_from_instance = self.label_from_instance

    @staticmethod
    def label_from_instance(obj):
        return "My Field name %s" % obj.name
Answered By: Thomas Turner

You can overwrite label_from_instance method of the ModelChoiceField instance to your custom method. You can do it inside the __init__ method of the form

class FooForm(forms.Form):
    person =  forms.ModelChoiceField(queryset=Person.objects.filter(is_active=True).order_by('id'), required=False)
    age = forms.IntegerField(min_value=18, max_value=99, required=False)

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

        self.fields['person'].label_from_instance = lambda instance: instance.name
Answered By: Abdullah Saquib

to chose/change the value you can use "to_field_name" options ,
and to change the label of option you can overwrite the "label_from_instance" function inside ModelChoiceField class,

and here is a simple example ,

forms.py:

from django import forms
from .models import Group
from django.forms import ModelChoiceField


class MyModelChoiceField(ModelChoiceField):
    def label_from_instance(self, obj):
        return f"My Object {obj.group_name}"


class MyPureDjangoForm(forms.Form):

    group = MyModelChoiceField(queryset=Group.objects.all(),
                                    widget=forms.Select(attrs={
                                        'class': 'form-control'
                                    }),
                                    to_field_name='id',                                   
                                    
                                    )

for more information’s kindly visit the following URL :

https://docs.djangoproject.com/en/3.2/ref/forms/fields/#django.forms.ModelChoiceField

i hope this helpful .

Answered By: K.A

Similar to Thomas’s answer, I recommend setting the label_from_instance method reference when creating the field. However, as I almost always want the model to have the same value for select field drop downs, I just define a get_select_field_label() method on the Model itself. This is especially useful when I want different select labels and __str__() representations. Heres a minimal example:

from django.db import models
from django import forms

class Book(models.Model):
    author = models.ForeignKey("Author", on_delete=models.CASCADE)
    title = models.TextField()
    
    def __str__(self):
        return f"{self.title}, by {self.author.full_name}"

    def get_select_field_label(self):
        return f"{self.title}"


class BookForm(forms.Form):
    title = forms.ModelChoiceField(queryset=Book.objects.all(), widget=forms.Select())

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['title'].label_from_instance = Book.get_select_field_label

Answered By: DJ Peach
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.