Gday, I am creating a site to manage data for software with django. Users on the site are linked to divisions (regions) in a divisions model through a many to many field. The actual data is all linked to profiles, which are owned by divisions. Division users can edit profiles owned by the division, but not others. My issue is with forms to create profiles.
Attached is an image of the form. The division field shows all divisions registered on the site, but I only want it to show ones that the logged in user is a member of. For example, this user is only a member of 'VATPAC' so it should only show that as an option to select. Attached is all the relevant code.
Forms.py
class ProfileForm(ModelForm):
class Meta:
model = models.Profile
fields = ('division', 'name')
widgets = {
'division': forms.Select(attrs={'class':'form-control'}),
'name': forms.TextInput(attrs={'class':'form-control'})
}
views.py
def AddProfile(request):
submitted = False
if request.method == "POST":
form = forms.ProfileForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('profile?submitted=true')
else:
form = forms.ProfileForm
if 'submitted' in request.GET:
submitted = True
return render(request,'profiles/create/create_profile.html', {'form': form, 'submitted': submitted})
models.py
class Profile(models.Model):
division = models.ForeignKey(Division, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
def __str__(self):
return self.name
models.py (foreignkey for division)
class Division(models.Model):
division_id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=6)
users = models.ManyToManyField(User)
def __str__(self):
return self.name
CodePudding user response:
You will want to override the __init__()
function of your form, pass in your current user, and filter the division queryset accordingly.
class MyForm(forms.ModelForm):
def __init__(self, user=None, *args, **kwargs): # note the additional user param
self.divisions = Division.objects.filter(users=user)
super(MyForm, self).__init__(*args, **kwargs)
self.fields['division'].queryset = self.divisions
When you call your form, be sure to pass in your request.user
as a named parameter.
Be aware that you will need to do a lot of filtering across your application to make sure that users can't interact with divisions they aren't related to. You have integer primary keys, so it wouldn't be difficult for a user to guess or at least try to access other divisions by enumeration. The code above wouldn't prevent someone from changing the value of your template's <select>
element and submitting it. You would need to clean the input before saving the form.