【问题标题】:Django post request is returning querydict instead of object id for model formDjango post请求返回querydict而不是模型表单的对象ID
【发布时间】:2020-08-07 21:51:08
【问题描述】:

我有模型

class CollectionForm(forms.ModelForm):
    Medicine_Name = forms.ModelChoiceField(queryset=Medicine.objects.all())
   
    class Meta:
        model = Medicine
        fields = ['Number_Of_Boxes', 'Last_Collected']

    def __init__(self, user = None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        if user:
            self.fields['Medicine_Name'].queryset=Medicine.objects.filter(User_Associated=user)

以及处理表单的视图:

def update(request, *args, **kwargs):
     

        
    if request.method == 'POST':
        qd = request.POST['chosen_medicine']
       
        instance = Medicine.objects.get(id=qd)    
        form = CollectionForm(request.POST,  instance=instance)
       
        if form.is_valid():                 
            instance = form.save(commit=False)                
            instance.save()
    else:
        form = CollectionForm() 
    context = {'form': form,
            'meds': Medicine.objects.filter(User_Associated=request.user),
    }

    return render(request, 'tracker/medicine_collection.html', context )

表格模板在这里:

<form method="POST" action = ''>
    {% csrf_token %}
    <label for="Medicine_Name">Medicine Name</label>
    <select class = "form-control" id = "Medicine_Name"  name = "chosen_medicine">
        {% for med in meds %}
          
            <option value = '{{med.auto_id}}'>{{ med.Medicine_Name }}</option>
        {% endfor %}
    
    </select>
           
    {{form.Number_Of_Boxes  }}
    
    {{form.Last_Collected }}
    
  
    <button class="btn btn-outline-info" type="submit">Create</button>
</form>

我正在尝试获取用户从下拉列表中选择的 Medicine_Name 的 ID。为此,我认为我有一个 POST 请求来获取 id。但是,在提交我的表单时出现错误:

Field 'id' expected a number but got <QueryDict: {'csrfmiddlewaretoken': ['rrkPEpuZqxWQ9TS4lLMRDwAQ7xZAOUVZl8iHLVfZJ8gEfKundDMvDh9oWp42l1Jf'], 'chosen_medicine': ['1'], 'Number_Of_Boxes': ['3'], 'Last_Collected': ['03/16/2020']}>.

如何确保 POST 请求实际获取 ID,而不是包含表单所有字段的查询字典?

【问题讨论】:

  • request.POSTuser 参数捕获。
  • 那么问题出在我的表单内的 init 方法中吗?我该如何补救?

标签: python django django-forms django-templates


【解决方案1】:

您可以定义构造函数,以便仍然保留位置参数:

class CollectionForm(forms.ModelForm):
   
    class Meta:
        model = Medicine
        fields = ['Number_Of_Boxes', 'Last_Collected']

    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        
        if user:
            self.fields['Medicine_Name'].queryset=Medicine.objects.filter(
                User_Associated=user
            )

然后在视图中将用户作为命名参数传递:

def update(request, *args, **kwargs):
    if request.method == 'POST':
        qd = request.POST['chosen_medicine']
        instance = Medicine.objects.get(id=qd)    
        form = CollectionForm(request.POST, instance=instance, user=request.user)
       
        if form.is_valid():                 
            instance = form.save()
    else:
        form = CollectionForm(user=request.user)
    context = {'form': form,
            'meds': Medicine.objects.filter(User_Associated=request.user),
    }
    return render(request, 'tracker/medicine_collection.html', context)

HTML 看起来也很“奇怪”,尤其是属性周围的间距:

<form method="POST" action="">
    {% csrf_token %}
    <label for="Medicine_Name">Medicine Name</label>
    <select class="form-control" id="Medicine_Name" name="chosen_medicine">
        {% for med in meds %}
            <option value="{{ med.id }}">{{ med.Medicine_Name }}</option>
        {% endfor %}
    </select>    
    {{ form.Number_Of_Boxes  }}
    {{ form.Last_Collected }}
    <button class="btn btn-outline-info" type="submit">Create</button>
</form>

注意:如果 POST 请求成功,请发送redirect [Django-doc] 实施Post/Redirect/Get pattern [wiki]。 这样可以避免在用户刷新时发出相同的 POST 请求 浏览器。

【讨论】:

  • 我实现了你的代码,但我现在收到错误Field 'id' expected a number but got ''. 所以它根本不再发布'chosen_medicine'。
  • 那么 taht 表示 HTML 表单中的 chosen_medicine 没有返回值(它返回了空字符串作为值)。但是表单与此无关,因此这是模板中的错误。 HTML 中的间距也看起来 奇数(如果不是无效的话)。
  • @Smasher640: 顺便说一句,这不应该是med.id 作为值吗?
  • @Smasher640:注意它确实发布了一些东西,否则它会引发KeyError
  • 太棒了,这样做后效果和预期一样。
【解决方案2】:

快速而混乱的东西可能会起作用。

data = dict(qd.iterlists())
instance = Medicine.objects.get(id=int(data.get('chosen_medicine')[0]))

但在我看来,如果你只需要一个 id,你甚至不应该发布整个查询集。

【讨论】:

  • 好吧,我需要在我的视图中发布所有要处理的字段,但我只需要最初的 id 来定义实例。有没有一种很好的方法可以将它们分开,而不会将它们一起发布在查询字典中?
猜你喜欢
  • 2021-08-10
  • 2011-02-04
  • 2016-07-03
  • 1970-01-01
  • 2020-11-12
  • 2014-02-10
  • 1970-01-01
  • 2018-08-23
  • 1970-01-01
相关资源
最近更新 更多