【问题标题】:Passing multiples Django Forms in context[] to templates将 context[] 中的多个 Django 表单传递给模板
【发布时间】:2017-09-03 13:11:45
【问题描述】:

我有一个自定义的 Django 用户模式来管理角色或用户类型:

  • 学生档案
  • 教授简介
  • 行政档案

由于我的 AbstractBaseUser 模型的一部分保持不变:

class User(AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(unique=True)
    username = models.CharField(max_length=40, unique=True)
    slug = models.SlugField(max_length=100, blank=True)
    is_student = models.BooleanField(default=False)
    is_professor = models.BooleanField(default=False)
    is_executive = models.BooleanField(default=False)

    other fields ...

我有 get_student_profile(),get_professor_profile()get_executive_profile() 方法来获取配置文件用户数据。

我已经在我的自定义模型User 中覆盖了save() 方法来保存配置文件数据,当is_student 或is_professor 或is_executive 已被检查以创建用户时,他们的数据将保存在各自的模型中:

class StudentProfile(models.Model):
    user = models.OneToOneField(User,on_delete=models.CASCADE)
    slug = models.SlugField(max_length=100,blank=True)
    origin_education_school = models.CharField(max_length=128)
    current_education_school = models.CharField(max_length=128)
    extra_occupation = models.CharField(max_length=128)

class ProfessorProfile(models.Model):
    CATHEDRAL_PROFESSOR = 'CATHEDRAL'
    RESEARCH_PROFESSOR = 'RESEARCH'
    INSTITUTIONAL_DIRECTIVE = 'DIRECTIVE'

    OCCUPATION_CHOICES = (
        (CATHEDRAL_PROFESSOR, 'Cathedral Professor'),
        (RESEARCH_PROFESSOR, 'Research Professor'),
        (INSTITUTIONAL_DIRECTIVE, 'Institutional Directive'),
    )
    user = models.OneToOneField(User,on_delete=models.CASCADE)
    slug = models.SlugField(max_length=100,blank=True)
    occupation = models.CharField(max_length=255,blank = False)

class ExecutiveProfile(models.Model):
    user = models.OneToOneField(User,on_delete=models.CASCADE)
    slug = models.SlugField(max_length=100, blank=True)
    occupation = models.CharField(max_length=255,blank = False)
    enterprise_name = models.CharField(max_length=255,blank = False)

我有每个个人资料用户的表格

class UserUpdateForm(forms.ModelForm):
    class Meta:
        widgets = {'gender':forms.RadioSelect,}
        fields = ("username", "email", "is_student",           "is_professor", "is_executive",)
        model = get_user_model() #My model User

class StudentProfileForm(forms.ModelForm):
    class Meta:
        model = StudentProfile
        fields = ('origin_education_school',current_education_school',
            'extra_occupation')

class ProfessorProfileForm(forms.ModelForm):
    class Meta:
        model = ProfessorProfile
        fields = ('occupation',)

class ExecutiveProfileForm(forms.ModelForm):
    class Meta:
        model = ExecutiveProfile
        fields = ('occupation', 'enterprise_name', 'culturals_arthistic','ecological')

我有这个 URL 可以访问个人资料用户

url(r"^profile/(?P<slug>[\w\-]+)/$",
        views.AccountProfilesView.as_view(
            model=ProfessorProfile),
            name='profile'
    ),

在我的AccountProfilesView 中,我管理个人资料表单并将它们发送到模板

class AccountProfilesView(LoginRequiredMixin, UpdateView):
    # All users can access this view
    model = get_user_model()
    success_url = reverse_lazy('dashboard')
    template_name = 'accounts/profile_form.html'
    fields = '__all__'

    def get_context_data(self, **kwargs):
        context = super(AccountProfilesView, self).get_context_data(**kwargs)
        user = self.request.user

        if not self.request.POST:
            if user.is_student:
                profile = user.get_student_profile()
                context['userprofile'] = profile
                context['form_student'] = forms.StudentProfileForm()
            elif user.is_professor:
                profile = user.get_professor_profile()
                context['userprofile'] = profile
                context['form_professor'] = forms.ProfessorProfileForm()
                print ("profesor form is", context['form_professor'])
            elif user.is_executive:
                profile = user.get_executive_profile()
                context['userprofile'] = profile
                context['form_executive'] = forms.ExecutiveProfileForm()
            elif user.is_student and user.is_professor and user.is_executive:
                student_profile = user.get_student_profile()
                professor_profile = user.get_professor_profile()
                executive_profile = user.get_executive_profile()
                context['student_profile'] = student_profile
                context['professor_profile'] = professor_profile
                context['executive_form'] = executive_profile

                student_form = forms.StudentProfileForm()
                professor_form = forms.ProfessorProfileForm()

                executive_form = forms.ExecutiveProfileForm()

                context['form_student'] = student_form
                context['form_professor'] = professor_form
                context['form_executive'] = executive_form
        return context

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = super(AccountProfilesView, self).post(request, *args, **kwargs)
        user = self.request.user
        if user.is_student:
            context['form_student'] = forms.StudentProfileForm(self.request.POST)
        elif user.is_professor:
            context['form_professor'] = forms.ProfessorProfileForm(self.request.POST)
        elif user.is_executive:
            context['form_executive'] = forms.ExecutiveProfileForm(self.request.POST)

        elif user.is_student and user.is_professor and user.is_executive:
            context['form_student'] = forms.StudentProfileForm(self.request.POST)
            context['form_professor'] = forms.ProfessorProfileForm(self.request.POST)
            context['form_executive'] = forms.ExecutiveProfileForm(self.request.POST)

        return context

    def form_valid(self, form):
        context = self.get_context_data(form=form)
        user = self.request.user
        user = form.save()
        if user.is_student:
            student = context['form_student'].save(commit=False)
            student.user = user
            student.save()
        elif user.is_professor:
            professor = context['form_professor'].save(commit=False)
            professor.user = user
            professor.save()
        elif user.is_executive:
            executive = context['form_executive'].save(commit=False)
            executive.user = user
            executive.save()

        elif user.is_student and user.is_professor and user.is_executive:
            student = context['form_student'].save(commit=False)
            student.user = user
            student.save()

            professor = context['form_professor'].save(commit=False)
            professor.user = user
            professor.save()

            executive = context['form_executive'].save(commit=False)
            executive.user = user
            executive.save()
        return super(AccountProfilesView, self).form_valid(form)

发生的情况是在get_context_data() 方法中context['form_professor'] = forms.ProfessorProfileForm()context['form_executive'] = forms.ExecutiveProfileForm() 没有传递给模板

当我使用学生个人资料 (is_student) 或教授个人资料 (is_professor) 或行政个人资料 (is_executive) 创建用户时,一切正常,这意味着,通过分隔的用户个人资料(用户只有一个配置文件)渲染表单配置文件根据要配置的字段显示表单。

从这个意义上说,在get_context_data() 部分中,以下代码可以工作并分别传递表单:

if user.is_student:
    profile = user.get_student_profile()
    context['userprofile'] = profile
    context['form_student'] = forms.StudentProfileForm()
elif user.is_professor:
    profile = user.get_professor_profile()
    context['userprofile'] = profile
    context['form_professor'] = forms.ProfessorProfileForm()
    print ("profesor form is", context['form_professor'])
elif user.is_executive:
    profile = user.get_executive_profile()
    context['userprofile'] = profile
    context['form_executive'] = forms.ExecutiveProfileForm()

但是当我创建一个用户并检查三个配置文件(is_studentis_professoris_executive)时,只需传递context['form_student'] = forms.StudentProfileForm()

我显示数据的模板是:

{% extends 'layout.html' %}
{% load bootstrap3 %}
{% block title_tag %}Accounts | Profile | iHost {{ block.super }}{% endblock %}
{% block body_content %}
<div class="container">
    <h1>My Profile</h1>
    <form method="POST">
        {% csrf_token %}

        # I ask for user profile of a separate way

        # Student Profile User  
        {% if userprofile.user.is_student %}
        <br/><hr>
            Student form
            {% bootstrap_form form_student %}
        {% endif %}

        # Professor Profile User  
        {% if userprofile.user.is_professor %}
            {{ form_professor.as_p }}
        {% endif %}

        # Executive Profile User       
        {% if userprofile.user.is_executive %}  
            {{ form_executive.as_p }}
           {% comment %} {% bootstrap_form form_executive %}{% endcomment %}
        {% endif %}

        # I ask for an user with three profiles

        {% if userprofile.user.is_student  %}
        <br/><hr>
        Student form
            {% if userprofile.user.is_professor %}
                {% if userprofile.user.is_executive %}
                    {% bootstrap_form form_student %}
                    <br/><hr>
                    Professor form does not arrive
                    {{ form_professor.as_p }}
                    {% comment %}  {% bootstrap_form form_professor %}{% endcomment %}
                    <br/><hr>
                    Executive form does not arrive
                    {{ form_executive.as_p }}    
                    {% comment %}
                    {% bootstrap_form form_student %}
                    {% bootstrap_form form_professor %}
                    {% endcomment %}         
                {% endif %}
            {% endif %}
        {% endif %}
<br /><br /><br />

        <input type="submit" value="Save Changes" class="btn btn-default">
    </form>
</div>

{% endblock %}

当我使用具有三个配置文件的用户登录并呈现配置文件表单时,我会得到与呈现的表单相关的这种行为。 form_professor 和 form_executive 未渲染

因此,我认为教授和执行表格实例没有传递给模板,

这也得到验证,因为如果我删除 cmets 并在我的模板中使用 django-bootstrap3 应用程序,我将无法获得 form_professorform_executive 实例表单

  • form_professor 未到达模板

  • form_executive 未到达模板

此外,虽然我认为这样我可以更好地执行我的模板中的条件逻辑。

我在这里发生了什么事。 我的想法是可以根据配置文件在一个模板中将配置文件表单呈现给用户。

我非常感谢他们的支持。


更新

根据下面的@Rohan 答案,确实,el ... if 语句是问题的根源。现在表单渲染良好。

我的AccountProfilesView 保持这种方式:

class AccountProfilesView(LoginRequiredMixin, UpdateView):
    # All users can access this view
    model = get_user_model()
    #success_url = reverse_lazy('dashboard')
    template_name = 'accounts/profile_form.html'
    fields = '__all__'

    def get_context_data(self, **kwargs):
        context = super(AccountProfilesView, self).get_context_data(**kwargs)
        user = self.request.user

        if not self.request.POST:
            if user.is_student:
                profile = user.get_student_profile()
                context['userprofile'] = profile
                context['form_student'] = forms.StudentProfileForm()
            if user.is_professor:
                profile = user.get_professor_profile()
                context['userprofile'] = profile
                context['form_professor'] = forms.ProfessorProfileForm()
                print ("profesor form is", context['form_professor'])
            if user.is_executive:
                profile = user.get_executive_profile()
                context['userprofile'] = profile
                context['form_executive'] = forms.ExecutiveProfileForm()
        return context

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = super(AccountProfilesView, self).post(request, *args, **kwargs)
        user = self.request.user
        if user.is_student:
            context['form_student'] = forms.StudentProfileForm(
                self.request.POST)
        if user.is_professor:
            context['form_professor'] = forms.ProfessorProfileForm(
                self.request.POST)
        if user.is_executive:
            context['form_executive'] = forms.ExecutiveProfileForm(
                self.request.POST)
        return context

    def form_valid(self, form):
        context = self.get_context_data(form=form)
        user = self.request.user
        user = form.save()
        if user.is_student:
            student = context['form_student'].save(commit=False)
            student.user = user
            student.save()
        if user.is_professor:
            professor = context['form_professor'].save(commit=False)
            professor.user = user
            professor.save()
        if user.is_executive:
            executive = context['form_executive'].save(commit=False)
            executive.user = user
            executive.save()
        return super(AccountProfilesView, self).form_valid(form)

    def get_success_url(self):
        return reverse('dashboard')

但是现在,当我想保存三个配置文件的表单部署产品时,我收到了这个错误消息。

File "/home/bgarcial/workspace/ihost_project/accounts/views.py", line 181, in post
    context['form_student'] = forms.StudentProfileForm(self.request.POST)
  File "/home/bgarcial/.virtualenvs/ihost/lib/python3.5/site-packages/django/http/response.py", line 142, in __setitem__
    value = self._convert_to_charset(value, 'latin-1', mime_encode=True)
  File "/home/bgarcial/.virtualenvs/ihost/lib/python3.5/site-packages/django/http/response.py", line 115, in _convert_to_charset
    raise BadHeaderError("Header values can't contain newlines (got %r)" % value)
django.http.response.BadHeaderError: Header values can't contain newlines (got '<tr><th><label for="id_origin_education_school">Origin education institute:</label></th><td><input id="id_origin_education_school" maxlength="128" name="origin_education_school" type="text" value="Universidad CES, Escuela de Ingeniería" required /></td></tr>\n<tr><th><label for="id_current_education_school">Current education institute:</label></th><td><input id="id_current_education_school" maxlength="128" name="current_education_school" type="text" value="Universidad CES" required /></td></tr>\n<tr><th><label for="id_extra_occupation">Extra occupation:</label></th><td><input id="id_extra_occupation" maxlength="128" name="extra_occupation" type="text" value="Networker" required /></td></tr>')
[08/Apr/2017 16:45:05] "POST /accounts/profile/milena/ HTTP/1.1" 500 108439

当要呈现表单时有些不便,我确保使用在 POST 方法中输入的数据填写此表单,但会发生该错误并且我会得到这个屏幕:

【问题讨论】:

    标签: python django django-forms django-templates django-views


    【解决方案1】:

    get_context_data 函数中的 python 代码存在问题。您不应使用if..elif.. 添加所需的表格。如果用户拥有所有个人资料,则使用您的代码,该代码只会进入第一个 if 并仅添加学生个人资料表单。

    因此,您应该为所有类型的配置文件使用单独的 if 语句。在这种情况下,您不需要所有类型的最后一个 ifanding。

    所以把你的代码改成

    if user.is_student:
        profile = user.get_student_profile()
        context['userprofile'] = profile
        context['form_student'] = forms.StudentProfileForm()
    
    #NOTE: no elif, only if
    if user.is_professor:
        profile = user.get_professor_profile()
        context['userprofile'] = profile
        context['form_professor'] = forms.ProfessorProfileForm()
        print ("profesor form is", context['form_professor'])
    
    if user.is_executive:
        profile = user.get_executive_profile()
        context['userprofile'] = profile
        context['form_executive'] = forms.ExecutiveProfileForm()
    
    # NO need for last if user.is_student and user.is_professor and user.is_executive:
    

    【讨论】:

    • 确实,el ... if 语句是问题的根源。现在表单渲染得很好。我很抱歉,这是一个新手错误。在这一刻,我的表格没有保存在数据库中。我认为对于 Django 来说,将要渲染和保存在 request.POST 实例中的表单很清楚。请在我原来的问题中检查我上面的 UPDATE。感谢您的指导。
    • @bgarcial,我不确定那个错误。为新问题发布新问题是一种很好的做法。
    • 你有理由。这个错误我已经解决了,但是我在其他问题中发布了另一个问题。让我与您分享这个新问题,以防您支持我。 stackoverflow.com/q/43314269/2773461
    猜你喜欢
    • 2016-11-17
    • 2017-03-02
    • 2012-08-24
    • 2012-09-27
    • 2021-05-20
    • 2019-01-11
    • 2012-09-27
    • 1970-01-01
    相关资源
    最近更新 更多