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)