Home > Blockchain >  Only displaying certain options in django form dropdown
Only displaying certain options in django form dropdown

Time:07-23

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.

enter image description here enter image description here

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.

  • Related