0

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

4

1 回答 1

0

我通过以下方式解决了我的问题。

首先,我将所有表单传递给字典中的模板,如下所示:

forms = {'email_form': email_form, 'password_form': password_form}
return render(request, 'settings.html', {'my_user'=user, 'forms'=forms})

然后我从带有自定义标签的字符串名称中获取表单:

@register.assignment_tag(name='get_form', takes_context=True)
def get_form(context, form_name):
    forms = context['forms']
    form = forms[form_name]
    return form

显然,如果我没有改变传递表单的方式,那么标签就会与 . 一起使用form = context[form_name],所以这个答案的重要部分是标签。

我仍然认为我的代码可以减少重复性,但至少它现在可以工作了!

于 2013-09-14T12:35:57.593 回答