Search code examples
pythondjangodjango-modelsdjango-formsforeign-keys

Python, Django: ForeignKey with dependencies (models.py)


Good day,

I would like to ask, if it's possible to determine an additional dependencie on a models.ForeignKey-field? For example ...

models.py

class Object_A(models.Model):
    name = models.Charfield(max_length=50, null=False, blank=False, unique=True)
    date_created = models.DateTimeField(auto_now_add=True)


class Object_B(models.Model):
    name = models.Charfield(max_length=50, null=False, blank=False, unique=True)
    object_a = models.ForeignKey(Object_A, null=False, blank=False, on_delete=models.CASCADE)
    date_created = models.DateTimeField(auto_now_add=True)


class Object_C(models.Model):
    name = models.Charfield(max_length=50, null=False, blank=False, unique=True)
    object_a = models.ForeignKey(Object_A, null=False, blank=False, on_delete=models.CASCADE)
    object_b = models.ForeignKey(Object_B, null=False, blank=False, on_delete=models.CASCADE)
    date_created = models.DateTimeField(auto_now_add=True)

forms.py

class Create_Object_C_Form(ModelForm):
    class Meta:
        model = Object_C
        exclude = [
            'object_a',
            'date_created',
        ]

What I'm trying to do...

As you can see, I'm excluding the object_a, because at this point inside my app where the form is used, the user doesn't have to choose for an object_a. His own steps have anticipated this choice! The same - or at least almost the same - goes for object_b: Is it possible to only show choices that are related to the same object_a?

Hoping I could explain my problem understandably and somebody can help or has an idea!? Have a great day!


Solution

  • You need to override your forms __init__ method and accept a keword argument that would indicate which Object_A instance is to be used:

    class Create_Object_C_Form(ModelForm):
        class Meta:
            model = Object_C
            exclude = [
                'object_a',
                'date_created',
            ]
       
        def __init__(self, *args, **kwargs):
            object_a = kwargs.pop('object_a') # get ObjectA from kwargs
            super().__init__(*args, **kwargs)
            self.fields['object_b'].queryset = object_a.object_b_set.all()
    

    Now when you create this form you would pass to it the instance of ObjectA you want to be using:

    Create_Object_C_Form(object_a=object_a)
    

    Note: Don't use _ in class names, it is against conventions. Particularly don't use them in Django, it leads to confusing lookups.