【问题标题】:Django foreign keys are not saving properlyDjango外键没有正确保存
【发布时间】:2018-02-19 23:11:37
【问题描述】:

我在同一个模型中有多个外键,由于某种原因,每当我在表单上点击提交时,最后一个外键都会覆盖之前输入的外键。任何人都可以看到发生了什么?

models.py

class Meal(models.Model):
    """
    Three of these will be given to a study
    """
    date = models.DateField(null=True, blank=True)
    start_time = models.TimeField(null=True, blank=True)
    stop_time = models.TimeField(null=True, blank=True)
    description = models.CharField(max_length=256, null=True, blank=True)

    class Meta:
        verbose_name_plural = 'Meals For Studies'

    def __str__(self):
        return "Meal Information for CRF # " + str(self.general_info.case_report_form_number)


class MotionStudyInstance(models.Model):
    # ###############ADD MEAL INFORMATION#######################
    meal_one = models.ForeignKey(Meal, related_name='first_meal', on_delete=models.CASCADE, null=True, blank=True)
    meal_two = models.ForeignKey(Meal, related_name='second_meal', on_delete=models.CASCADE, null=True, blank=True)
    meal_three = models.ForeignKey(Meal, related_name='third_meal', on_delete=models.CASCADE, null=True, blank=True)

    class Meta:
        verbose_name_plural = 'Motion Studies Awaiting Validation'

    def __str__(self):
        return "CRF: #" + str(self.general_info.case_report_form_number)

forms.py

class MealForm(forms.ModelForm):
    class Meta:
        model = Meal

views.py

class MotionStudyInstanceFormView(LoginRequiredMixin, View):
        def post(self, request):
            if request.method == 'POST':
                    form = MotionStudyInstanceForm(request.POST, request.FILES)
                    meal_one_form = MealForm(request.POST)
                    meal_two_form = MealForm(request.POST)
                    meal_three_form = MealForm(request.POST)
                    if meal_one_form.is_valid() and meal_two_form.is_valid() and meal_three_form.is_valid():
                        meal_one = meal_one_form.save()
                        meal_two = meal_two_form.save()
                        meal_three = meal_three_form.save()
                        motion_study_instance_one = form.save(commit=False)
                        motion_study_instance_one.meal_one = meal_one
                        motion_study_instance_one.meal_two = meal_two
                        motion_study_instance_one.meal_three = meal_three
                        motion_study_instance_one.save()
                        return redirect('data:motion-studies')
            else:
                 form = MotionStudyInstanceForm()
        return render(request, self.template_name, {'form': form})

motionstudyinstance_form.html

{% extends "base.html" %}
{% load bootstrap3 %}
{% block content %}
<div class="container">
    <h1>Motion Study Form</h1>
    <form method="POST" enctype="multipart/form-data">
        {% bootstrap_form form %}
        <p>Meal One Information</p>
        {% bootstrap_form meal_one_form %}
        <p>Meal Two Information</p>
        {% bootstrap_form meal_two_form %}
        <p>Meal Three Information</p>
        {% bootstrap_form meal_three_form %}
        <input class="btn btn-default" type="submit" value="Submit">
    </form>
</div>

{% endblock %}}

就像我说的,当我保存表格时,前两个用餐条目被覆盖,看起来像第三个的副本。我究竟做错了什么?我是 Django 新手。

【问题讨论】:

  • 三种表单的request.POST不一样吗?
  • 什么意思?
  • 你说“前两个饭菜条目被覆盖,看起来像第三个的副本”,我认为这三个表单将始终具有相同的值,因为它们从 request.POST 收到相同的请求跨度>
  • 我为每顿饭提供了单独的表格。我将如何为每个请求单独提出请求?
  • 那你如何提交这些froms?逐个?。如果是这样,您可以更改每个表单的操作。如果在单个表单中呈现他们的字段数据,则可以根据 POST 数据中的字段名称确定提交哪个表单

标签: django django-models django-forms django-views foreign-keys


【解决方案1】:

我想知道为什么要在一个 html 表单中复制三次相同的表单。但是 request.POST 将始终具有相同的值。 即:尽管您复制了表单,但 Django 生成的输入将具有相同的名称。

description = models.CharField(max_length=256, null=True, blank=True)

{{form.description}} 

会生成

<input type="text" name="description" id="id_description" maxlength="256">

即使复制 {{form}} 两次,名称仍然是每个表单的描述。

所以 request.POST["description"] 包含收到的最后一个或第一个值。

您可以在模板中生成 3 个表单,在一个简短的 get 参数之后执行不同的操作。

<form action="/your_url/?form=1" method="post">
    {% bootstrap_form form %} <!-- the first form -->
    <!-- enter code here, with the submit button -->
</form>

<form action="/your_url/?form=2" method="post">
    {% bootstrap_form form %}<!-- the second form -->
    <!-- enter code here, with the submit button-->
</form>

<form action="/your_url/?form=3" method="post">
    {% bootstrap_form form %}<!-- the third form -->
    <!-- enter code here, with the submit button-->
</form>

您还可以为每个表单使用隐藏输入,以便准确了解提交的表单

<form action="/your_url/" method="post">
    {% bootstrap_form form %}<!-- the second form -->
    <input type="hidden" name="form" value="3">
    <!-- enter code here, with the submit button-->
</form>

在你看来:

if request.method == 'POST':
    form = MotionStudyInstanceForm(request.POST, request.FILES)
    # If GET parameter
    w = request.GET.get("form","") # form 1 , 2 or 3
    # If Hidden Input
    # w = request.POST.get("form","")
    if w == "1":
        pass

【讨论】:

  • 我的目标是在同一页面上显示表单并使用一个提交按钮将它们全部提交。然后 post 方法将挂钩后端的外键。我明白您对 POST['description'] 的看法,但是是否可以按照您在上面显示的操作并仍然使用一个提交按钮在同一页面上呈现表单?
  • 你可以这样做:form1 = MotionStudyInstanceForm(), form2 = MotionStudyInstanceForm(), form3 = MotionStudyInstanceForm() return render(request, self.template_name, {'form1': form1,'form2' :form2,'form3':form})。但在模板中,这将是多余的,因为每个输入字段将通过 3 个表单具有相同的名称。解释你想做什么,这可能是另一种方法,而不是由同一个提交按钮触发内部的 3 个表单
  • 嗯,我的目标是渲染多个表单,然后在后端连接外键关系。这样用户只看到一个表单,不知道后端在做什么。一切正常,直到我来到三种膳食形式。如果我能找到一种方法来呈现三种膳食表格并正确保存它们,那么我将在完成该网站的路上。问题是我不知道如何正确保存三种单独的膳食形式,而不会被覆盖。
  • 我需要做的就是同时渲染三个餐单并正确保存。
  • 这是否是您要显示 3 次的同一个表单,对吗?您可以显示一次表单并添加这些按钮:“提交”“提交和添加其他”,如果用户选择第二个选项,您将重定向到空表单(最多 3 次)。处理外键关系。最好的方法是在将实例链接到 MotionStudyInstance 模型之前和之后创建 Meal。我没有看到用户在哪里链接到 MotionStudyInstance BTW
【解决方案2】:

下面的代码不是最好的方法,但如果我理解你想要做什么,它就会成功。

HTML:此处需要更多验证

<form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
    {% for i in 'aaa' %} <!-- A way to duplicate three times ,foorloop with make them different -->
    <input type="text" required name="description{{forloop.counter}}" id="id_description{{forloop.counter}}">
    <input type="date" required name="date{{forloop.counter}}" id="id_date{{forloop.counter}}">
    <input type="text" required name="start_time{{forloop.counter}}" id="id_start_time{{forloop.counter}}">
    <input type="text" required name="stop_time{{forloop.counter}}" id="id_stop_time{{forloop.counter}}">
    {% endfor %}
    <button type="submit">Submit</button>
</form>

VIEWS:此处还需要更多验证

if request.method == 'POST':
    n = {"1":"one","2":"two","3":"three"}
    # Create The Instance of MotionStudyInstance
    motion_study = MotionStudyInstance.objects.create()
    for i in range(1,4):
        i = str(i) # in order to concatane with string
        date = request.POST.get("date"+i,"")
        start_time = request.POST.get("start_time"+i,"")
        stop_time = request.POST.get("stop_time"+i,"")
        description = request.POST.get("description"+i,"")

        # Test if everything is ok with each input fields

        m = Meal.objects.create(
            date = date ,
            start_time = start_time,
            stop_time = stop_time,
            description = description,
        )   
        eval("motion_study.meal_"+n[i]) = m

    # Finally save the instance
    motion_instance.save()

【讨论】:

  • 我会看看我能做些什么,如果出现任何问题,请告诉您。感谢大家的帮助!
猜你喜欢
  • 2013-01-09
  • 2011-04-26
  • 1970-01-01
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 2016-03-23
  • 1970-01-01
  • 2017-05-10
相关资源
最近更新 更多