pythondjangodjango-formsmodelchoicefield

Displaying fields other than pk in a Django Form with a ModelChoiceField


I am building a website where users can upload files and can attach uploads to projects that they created beforehand. The upload is done with a django form where the user can specify the title, comments, etc... There is also a dropdown list where the user can choose from the existing projects that he created (list of projects is dependent on user) As of now the dropdown only shows the (autogenerated) project id which is the pk of the model Project.

I want the dropdown to show the names of the projects and not the project ID which is not very meaningful for the user.

I have already tried

to_field_name='name' 

but that didn't work

I have also tried

Project.objects.filter(user=user).values_list('name')

or

Project.objects.filter(user=user).values('name')

the last two options show the project name in {'projectname} but when I select them and submit the form the error "Select a valid choice. That choice is not one of the available choices."

This is my code:

models.py

class Upload(models.Model):
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    upload_date = models.DateTimeField(default=timezone.now)
    comments = models.CharField(max_length=10000, null=True)
    title = models.CharField(max_length=10000, null=True)
    project = models.CharField(max_length=99, default='--None--')

forms.py

class UploadForm(ModelForm):
    project = ModelChoiceField(label='Select Project', queryset=Project.objects.all(), to_field_name='name',
                               empty_label='--Select Project--')

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)
        super(UploadForm, self).__init__(*args, **kwargs)
        if user is not None:
            self.fields['project'].queryset = Project.objects.filter(user=user)

    class Meta:
        model = Upload
        fields = ['title', 'project', 'upload_date', 'comments']

Solution

  • According to docs

    The str() 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.

    https://docs.djangoproject.com/en/2.2/ref/forms/fields/#modelchoicefield

    so you should define __str__() method for Project model e.g.

    def __str__(self):
        return self.name