I have a multi-tenant app where each "tenant" (Company model object) have multiple clients. Each tenant may set up which required fields they need for their app.
class Client(models.Model):
"""
Client information
"""
company = models.ForeignKey(Company, blank=True, null=True, default=1, on_delete=models.SET_NULL)
name = models.CharField(max_length=150, blank=True)
email = models.EmailField(max_length=255, unique=True)
phone_number = models.CharField(max_length=50, blank=True, null=True)
class RequiredClientFields(models.Model):
"""
Let each business decide how to enforce the data filling requirements for its staff/clients.
0 - dont even show it
1 - show it, but dont require (default)
2 - require field for either staff or client
3 - require for clients when self-filling their form, but not the staff members
"""
company = models.ForeignKey(Company, db_index=True, on_delete=models.CASCADE)
field_name = models.CharField(max_length=50)
status = models.PositiveSmallIntegerField(choices=FIELD_STATUS_CHOICES, default=1)
So, when creating the django forms to use on the template, whats to best way to display (and validate) each field according to the Company's policies?
thanks
Something like this might work.
Declare a ModelForm and overwrite __init__()
with logic to delete fields or change their required
status:
class ClientForm(forms.ModelForm):
class Meta:
model = Client
fields = '__all__'
def __init__(self, company, user, *args, **kwargs):
super(ClientForm, self).__init__(*args, **kwargs)
# For each RequiredClientFields instance,
# get the matching form field and make changes
for rule in RequiredClientFields.objects.filter(company=company):
# get the form field
field = self.fields.get(rule.field_name, None)
if field:
if rule.status == 0:
# remove field from form
self.fields.pop(rule.field_name)
elif rule.status == 2:
# require field
field.required = True
elif rule.status == 3 and not user.is_staff:
# require for clients when self-filling their form,
# but not the staff members
field.required = True
Then create an instance of the ModelForm in your view, passing arguments for the company and user.
company = Company.objects.get(pk=1)
client_form = ClientForm(company=company, user=request.user)
Be aware that there are potential security implications when controlling form fields this way. Take a look at the relevant section in the Django ModelForm docs.