pythondjangodjango-modelsmodelchoicefield

Django field with foreignKey


I'm using Django v4.1 and have a foreignKey relationship I want to pull into a form.

The two models:

class Service(models.Model):
   client = models.ForeignKey("Client", on_delete=models.SET_NULL, null=True)
   # some other fields

and

class Client(models.Model):
    name = models.CharField(max_length=50)
    # a few more fields

The form:

class ServiceForm(forms.ModelForm):
    class Meta:
        model = Service
        fields = "__all__"

However, in the front-facing form, "Client" is generated, but without a SELECT field.

There is another model with a foreignKey relationship to Client, order:

class Order(models.Model):
    client = models.ForeignKey("Client", on_delete=models.SET_NULL, null=True)
    # more fields...

And it's form:

class OrderModelForm(forms.ModelForm):
    class Meta:
        model = Order
        fields = "__all__"

Which renders as expected with a SELECT field for the Client.

Looking at the forms docs I experimented with (importing Client from models and) adding a ModelChoiceField, ("client": forms.ModelChoiceField(queryset=Client.objects.all()) both inside and outside of a widgets dict), but based on this SO post I'm thinking Django should be rendering that on it's own, as it is for Order.

Please share suggestions in debugging. Thanks much.


Solution

  • Found it!

    Even though I've been managing this project for a while, there are a lot of gaps in my Django knowledge. So I made a new Django app and app, adding a myapp/models.py with a minimized version of the problem app:

    from django.db import models
    from django.utils import timezone
    
    class Client(models.Model):
        name = models.CharField(max_length=50)
        email = models.EmailField(blank=True, null=True)
    
        def __str__(self):
            return self.name
    
    
    class Order(models.Model):
        created = models.DateTimeField(auto_now_add=True)
        client = models.ForeignKey("Client", on_delete=models.SET_NULL, null=True)
    
    
    class Service(models.Model):
        client = models.ForeignKey("Client", on_delete=models.SET_NULL, null=True)
        name = models.CharField(max_length=50)
    

    Sure enough, the SELECT fields were there for Client in both Service and Order views.

    The barebones app doesn't even have a forms.py file in it, so I thought, what if I remove my ServiceForm(ModelForm) (from the real project) altogether?

    But this raised an Exception because admin.py is importing ServiceForm from forms.

    Hmmm. I hadn't thought to look in class ServiceAdmin.

    Lo and behold:

    readonly_fields = (
        "client",
        etc...
    )
    

    Removed that line and the SELECT field is there as expected.