Clean way to customize forms based on user's group in Django

I want to customize my model's forms based on user's group. The customization that I am talking about are small, but to give you an idea, my "customizations" would be something like :

  • users within GroupA would have a BooleanField with True as default, even though default is False for others
  • users within GroupB would have a CharField (input text) hidden (not changeable)
  • users within groupC would have not the same options as others for a CharField with options (different options in select)
  • ...

Currently, I actually achieved to do this by doing a mix of logic in my views.py and in my forms.py.

But I don't really like to mix logic in 2 different files, so I came to ask your opinion about which is the best (cleanest) way in your opinion and how to achieve it.

Here are the 2 technics that I think of:

1. Creating a form for each group in forms.py.

This would be the cleanest way imo.
By creating a form for every group (MyModelGroupAForm(ModelForm), MyModelGroupBForm(ModelForm), ...) , I can easily change a field/input/... in my forms.py file everytime that a change is requested and/or a group is created.
Then, all I have to do is to change to override the get_form(self) method in my MyModelCreateView and MyModelUpdateView, and to change the self.form_class to the correct form based on the user's group like below:

Class MyModelCreateView(CreateView):
    model = MyModel
    form_class = MyModelDefaultForm
    
    def get_form(self):
        if self.request.user.groups.filter(name='GroupA').exists():
            self.form_class = MyModelGroupAForm
        elif self.request.user.groups.filter(name='GroupB').exists():
            self.form_class = MyModelGroupBForm
        elif ...  # another group
        
        form = super().get_form()
        return form
    
    ...

The downside of this technic is that I will have to make a lot of forms with generally the same data: for example, one of my field is asking for a widget. Meaning that EVERY form that I create for EVERY group will have to specify my_field = forms.CharField(widget=DatePickerInput()), since specifying the widget in the model definition in models.py is not possible. This seems not really DRY... (is there some sort of inheritance between forms ? If I could make a form inherit from an abstract form, I wouldn't have to define my field every time)

2. Handling all the logic in the views.py.

It makes my views.py file very long...
Basically, in my MyModelCreateView class in my views.py, I would change a field in the get_form() method based on self.request.user's group. And there I would implement a lot of if/else/switchlike logic based on the group and change every fields, like below:

Class MyModelCreateView(CreateView):
    model = MyModel
    form_class = MyModelDefaultForm
    
    def get_form(self):
    
        form = super().get_form()

        if self.request.user.groups.filter(name='GroupA').exists():
            # change the default of a boolean field to True, instead of False
            # another change specific to group A making the method even longer
            # ...
        elif self.request.user.groups.filter(name='GroupB').exists():
            # hide/remove a CharField
            # another change specific to group B making the method even longer
            # ...
        elif ... # another group

        return form

Imo, it's not very clean. For now I have less than 10 groups, so it's mokay. But later I will have way more groups, meaning that my if/elif/elif/... logic will be huge... Also, I would need to copy paste this logic to the MyModelUpdateView as well...
Not really DRY...

What do you think ? What's the best/cleanest way to do it ?

(For now I'm doing a mix of technic 1 and technic 2 btw)

Back to Top