mike_gundy123
mike_gundy123

Reputation: 499

How to generate a choices tuple for django models field to use in a form

Trying to create a choice field based on another model

I want my choices to be mapped like username: first_name + last_name

When I try username: last_name it does work

I tried doing something like this(Note, I am adding on user_choices and choices=user_choices. The model already existed before me making these changes.)

This works:

he_user_choices = tuple(User.objects.values_list('username', 'last_name'))

Here's what my models.py looks like:

from django.contrib.auth.models import User

owner_choices = tuple(User.objects.values_list('username', 'first_name' + 'last_name'))


class ErrorEvent(models.Model):
    """Error Event Submissions"""
    event_id = models.BigAutoField(primary_key=True)
    owner = models.IntegerField(verbose_name="Owner", blank=True, choices=owner_choices)

and here's my forms.py

from django import forms
from .models import ErrorEvent


class ErrorEventForm(forms.ModelForm):

    class Meta:
        model = ErrorEvent
        # fields =
        exclude = ['event_id']
        widgets = {
            'owner': forms.Select(),
        }

Currently the owner_choices doesn't work, I get an error that says:

django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.

Any recommendations on what else I can try, or how would I go about fixing my problem?

Thank you in advance!

Upvotes: 1

Views: 1382

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477210

Please do not work with an IntegerField to refer to an object. A ForeignKey will check referential integrity, and furthermore it makes the Django ORM more expressive.

You thus can implement this with:

from django.conf import settings

class ErrorEvent(models.Model):
    event_id = models.BigAutoField(primary_key=True)
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        verbose_name='Owner',
        blank=True,
        null=True
    )

This will work with a ModelChoiceField [Django-doc] that automatically will query the database to render options. This also means that if you add a new User, creating a new ErrorEvent can be linked to that user, since it each time requests the Users from the database.

You can subclass the ModelChoiceField to specify how to display the options, for example:

from django.forms import ModelChoiceField

class MyUserModelChoiceField(ModelChoiceField):

    def label_from_instance(self, obj):
        return f'{obj.username} ({obj.firstname} {obj.lastname})'

Then we can use this in the form:

class ErrorEventForm(forms.ModelForm):
    owner = MyUserModelChoiceField(queryset=User.objects.all())

    class Meta:
        model = ErrorEvent
        # fields =
        exclude = ['event_id']
        widgets = {
            'owner': forms.Select(),
        }

Upvotes: 1

Related Questions