I have a user settings page with multiple editable and non-editable components. Each editable component has its own form. All of the components are displayed in a table, with the contents coming from a dict on the model. For example:
class MyUser(models.AbstractBaseUser):
def get_settings(self):
return [
('Email Address',
{'value': self.email, 'editable': True, 'section': 'email', 'form': 'email_form'}
),
('Password',
{'value': '', 'editable': True, 'section': 'password', 'form': 'password_form'})]
I then have a form defined for each item in the settings, such as:
class ChangeEmailForm(models.ModelForm):
class Meta:
fields = ['email']
model = models.MyUser
email = forms.EmailField(widget = forms.TextInput(attrs={'placeholder': 'Email Address'}))
All of the forms are handled by one view, and in that view they are assigned a name, which matches the name in the settings data on the model:
def edit_settings_view(request, user):
if request.POST:
if 'email_form' in request.POST:
if email_form.is_valid():
email_form.save()
return HttpResponseRedirect('/settings/')
else:
form_errors = email_form.errors
return render(request, 'settings.html', {'my_user'=user, 'email_form'=email_form, 'form_errors'=form_errors})
else:
email_form = ChangeEmailForm(instance=user)
return render(request, 'settings.html', {'my_user'=user, 'email_form'=email_form})
The trouble comes when trying to render the forms in the template. I currently have:
{% for key, value in my_user.get_settings %}
<form action="{% url "edit_profile" %}" method="post">
{% csrf_token %}
<p>
{% for field in value.form %}
{{ field }}
{% endfor %}
<button type="submit" name=value.form>Save</button>
</p>
</form>
However, this just prints the name of the form, e.g 'email_form'. I understand why that's happening, but I don't know how I can get the template to display the form instead. Also, is there a better way of handling the user settings? The code I've shown here is very cut down, but it's basically repeated for each different setting, which isn't very DRY