How to find column based on FK inside forms.py?

Hello, I want to show data from another table based on the FK that is inside the normal table through my forms.py file.

My forms.py:

#================WEGINGEN================#
#========================================#
class WegingenInvoegenForm(forms.ModelForm):
    class Meta:
        model = Wegingen
        fields = ['aantalTonICT', 'aantalTonServers', 'aantalTonElektro', 'aantalTonGSMIncl',
                    'aantalTonGSMExcl', 'aantalTonGrootWitgoed', 'aantalTonKoelVries',
                    'aantalTonRestafval', 'gebruiker', 'levering', 'ophaling']

        widgets = {
            'gebruiker': s2forms.ModelSelect2Widget(model = User, attrs={'data-placeholder':_("ContactNaam")}, queryset = User.objects.filter(is_superuser=False), search_fields = ['contactNaam__icontains']),
            'levering' : s2forms.ModelSelect2Widget(model = Leveringen, attrs={'data-placeholder':_("LeveringsAdres")}, search_fields = ['leveringsAdres__icontains'] ),
            'ophaling' : s2forms.ModelSelect2Widget(model = Ophalingen, attrs={'data-placeholder':_("OphalingsAdres")}, search_fields = ['ophaling.ophalingsAdres__icontains'] ),
        }

    aantalTonICT = forms.FloatField(
        initial = None,
    )
    aantalTonServers = forms.FloatField(
        initial = None,
    )
    aantalTonElektro = forms.FloatField(
        initial = None,
    )
    aantalTonGSMIncl = forms.FloatField(
        initial = None,
    )
    aantalTonGSMExcl = forms.FloatField(
        initial = None,
    )
    aantalTonGrootWitgoed = forms.FloatField(
        initial = None
    )
    aantalTonKoelVries = forms.FloatField(
        initial = None,
    )
    aantalTonRestafval = forms.FloatField(
        initial = None,
    )

As you can see I’m trying to use Select2 to search things like ‘leveringsAdres’ and ‘ophalingsAdres’. I can actually search based on the data of these columns, but in the select field the ID (Foreign Key) of ‘levering’ and ‘ophaling’ just gets displayed for me to select. I want the real values to be shown and underlying the ID.

Is there any way I can do this?

My models.py file:

from django.db import models
from datetime import datetime
from django.contrib.auth.models import AbstractUser

# Create your models here.
class User(AbstractUser):
    bedrijfsNaam            = models.CharField(max_length=300)
    contactNaam             = models.CharField(max_length=300)
    adres                   = models.CharField(max_length=300)

    def __str__(self):
        return self.contactNaam

class Service(models.Model):
    referentie              = models.CharField(max_length=250)
    leveringsDatum          = models.DateField(default=datetime.now, blank=True)
    ophalingsDatum          = models.DateField(default=datetime.now, blank=True)
    wegingLevering          = models.FloatField(default=0)
    wegingOphaling          = models.FloatField(default=0)
    aantalBoxen             = models.IntegerField(default=0)
    aantalRolcontainers     = models.IntegerField(default=0)
    aantalPaletten          = models.IntegerField(default=0)
    aantalDozenCartridges   = models.IntegerField(default=0)
    afrekening              = models.FloatField(default=0)
    gebruiker               = models.ForeignKey(User, on_delete=models.CASCADE)

class Prijzen(models.Model):
    leveringsKost           = models.FloatField(default=0)
    ophalingsKost           = models.FloatField(default=0)
    huurKost                = models.FloatField(default=0)
    percentKlant            = models.FloatField(default=0)
    percentBedrijf          = models.FloatField(default=0)
    ictPremium              = models.FloatField(default=0)
    servers                 = models.FloatField(default=0)
    elektroPremium          = models.FloatField(default=0)
    kleineApparaten         = models.FloatField(default=0)
    gsmINCL                 = models.FloatField(default=0)
    gsmEXCL                 = models.FloatField(default=0)
    grootWitgoed            = models.FloatField(default=0)
    profKoelvries           = models.FloatField(default=0)
    restAfval               = models.FloatField(default=0)
    inkoopLeveringsKost     = models.FloatField(default=0)
    inkoopOphalingsKost     = models.FloatField(default=0)
    inkoopHuurKost          = models.FloatField(default=0)
    inkoopICTPremium        = models.FloatField(default=0)
    inkoopServers           = models.FloatField(default=0)
    inkoopElektroPremium    = models.FloatField(default=0)
    inkoopKleineApparaten   = models.FloatField(default=0)
    inkoopGSMINCL           = models.FloatField(default=0)
    inkoopGSMEXCL           = models.FloatField(default=0)
    inkoopGrootWitgoed      = models.FloatField(default=0)
    inkoopProfKoelvries     = models.FloatField(default=0)
    inkoopRestAfval         = models.FloatField(default=0)
    slug                    = models.SlugField(null=True)

class Leveringen(models.Model):
    leveringsAdres          = models.CharField(max_length=250)
    datum                   = models.DateTimeField(auto_now_add=True)
    aantalRolcontainers     = models.FloatField(default=0)
    aantalBoxes             = models.FloatField(default=0)
    gebruiker               = models.ForeignKey(User, on_delete=models.CASCADE)

class Ophalingen(models.Model):
    ophalingsAdres          = models.CharField(max_length=250)
    datum                   = models.DateTimeField(auto_now_add=True)
    aantalRolcontainers     = models.FloatField(default=0)
    aantalBoxes             = models.FloatField(default=0)
    aantalPaletten          = models.FloatField(default=0)
    aantalDozen             = models.FloatField(default=0)
    gebruiker               = models.ForeignKey(User, on_delete=models.CASCADE)

class Wegingen(models.Model):
    aantalTonICT            = models.FloatField(default=0)
    aantalTonServers        = models.FloatField(default=0)
    aantalTonElektro        = models.FloatField(default=0)
    aantalTonGSMIncl        = models.FloatField(default=0)
    aantalTonGSMExcl        = models.FloatField(default=0)
    aantalTonGrootWitgoed   = models.FloatField(default=0)
    aantalTonKoelVries      = models.FloatField(default=0)
    aantalTonRestafval      = models.FloatField(default=0)
    gebruiker               = models.ForeignKey(User, on_delete=models.CASCADE)
    levering                = models.ForeignKey(Leveringen, on_delete=models.CASCADE)
    ophaling                = models.ForeignKey(Ophalingen, on_delete=models.CASCADE)

Look at the label_from_instance method on the Widget class.

So I have to write a class that returns the data of a single column and than I have to call upon that class inside my modelForm to overwrite what get’s shown inside that select field on the front-end?

No, it’s a bit easier than that.

You create a class that inherits from ModelSelect2Widget.
You define a method in that class named label_from_instance(self, obj).
That method (which receives an individual object) then returns the value you want shown.
You then use that object as the Widget class in your widgets dict.

Now, to keep from having to create a separate widget class for each model, define a method in each model. (For discussion purposes, let’s call it get_select2_repr) Your label_from_instance method might then look like this:

class MyModelSelect2Widget(ModelSelect2Widget):
    def label_from_instance(self, obj):
        return obj.get_select2_repr()

and then widgets start to look like this:

widgets = {
            'gebruiker': MyModelSelect2Widget(model = User, attrs={'data-placeholder':_("ContactNaam")}, queryset = User.objects.filter(is_superuser=False), search_fields = ['contactNaam__icontains']),
...

Caveat - haven’t tried this, I’m winging this off-the-cuff. This could all fail miserably.

You are an actual genius man, it works!