Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django表单:隐藏字段中的外键_Python_Django_Forms - Fatal编程技术网

Python Django表单:隐藏字段中的外键

Python Django表单:隐藏字段中的外键,python,django,forms,Python,Django,Forms,我的表格: class PlanForm(forms.ModelForm): owner = forms.ModelChoiceField(label="", queryset=Profile.objects.all(), widget=forms.HiddenInput()) etc... class Meta:

我的表格:

class PlanForm(forms.ModelForm):    
    owner = forms.ModelChoiceField(label="",
                                  queryset=Profile.objects.all(),
                                  widget=forms.HiddenInput())
    etc...

    class Meta:
        model = Plan
在模型中,所有者是配置文件的外键

当我设置此表单时,我将“owner”的值设置为Profile对象

但当这出现在表单上时,它似乎包含如下配置文件的名称:

<input type="hidden" name="owner" value="phil" id="id_owner" />
    form = PlanForm(request.POST)
    ...
    if form.is_valid():                
        plan = form.save()
        return HttpResponseRedirect('/plans/%s'%plan.id) # Redirect after POST
但是,我得到的是一个类型转换错误,因为它无法将字符串“phil”(保存在“owner”字段中的用户名)转换为Int,从而将其转换为ForeignKey


那么这里发生了什么。ModelForm是否应该将外键表示为数字并透明地处理它?或者我需要自己将id提取到表单的所有者字段中吗?如果是这样,在我尝试验证表单之前,我应该如何以及何时将其映射回

通常不需要将相关对象放入表单字段中。有一种更好的方法,这就是在表单URL中指定父id

假设您需要为新的计划对象呈现一个表单,然后在表单提交时创建一个表单。以下是您的urlconf的外观:

(r"/profile/(?P<profile_id>\d+)/plan/new", view.new_plan), # uses profile_id to define proper form action
(r"/profile/(?P<profile_id>\d+)/plan/create", view.create_plan) # uses profile_id as a Plan field
(r)/profile/(?P\d+)/plan/new),view.new#使用profile#id定义正确的表单操作
(r“/profile/(?P\d+)/plan/create”,view.create_plan)#使用profile_id作为计划字段

如果要更改现有对象,只需使用plan_id,就可以从中推断出任何相关记录。

将配置文件对象指定给表单时,Django将其字符串化,并将输出用作表单中的值。不过,您希望Django使用对象的ID

幸运的是,解决方法很简单:只需为表单提供概要文件对象的主键值即可:

form = PlanForm(initial={'profile': profile.pk})
另一方面,当您使用绑定表单时,它们的工作更加合理:

form = PlanForm(request.POST)
if form.is_valid():
    print form.cleaned_data['profile']  # the appropriate Profile object

我怀疑Profile model实例的
\uuuuunicode\uuuuu
方法或其
repr
被设置为返回除
self.id
之外的值。例如,我刚刚设置了以下内容:

# models.py
class Profile(models.Model):
    name = models.CharField('profile name', max_length=10)

    def __unicode__(self):
        return u'%d' % self.id

class Plan(models.Model):
    name = models.CharField('plan name', max_length=10)
    profile = models.ForeignKey(Profile, related_name='profiles')

    def __unicode__(self):
        return self.name


# forms.py
class PlanForm(forms.ModelForm):
    profile = forms.ModelChoiceField(queryset=Profile.objects.all(),
            widget=forms.HiddenInput())

    class Meta:
        model = Plan

# views.py
def add_plan(request):

    if request.method == 'POST':
        return HttpResponse(request.POST['profile'])


    profile = Profile.objects.all()[0]
    form = PlanForm(initial={'profile':profile})
    return render_to_response('add_plan.html',
            {
                'form':form,
            },
            context_instance=RequestContext(request))
这样,我就可以在模板中看到这样呈现的PlanForm.profile:

<input type="hidden" name="profile" value="1" id="id_profile" />

这实际上可能是一个安全漏洞

假设一个恶意攻击者制作了一篇帖子(比如,通过使用FireBug中的XmlHttpRequest),并将配置文件术语设置为一些古怪的值,例如,您的配置文件ID。可能不是您想要的

如果可能,您可能希望从请求对象本身获取概要文件,而不是从POST值中提交的内容

form = PlanForm(request.POST)
if form.is_valid():
    plan = form.save(commit=False)
    plan.owner = request.user.get_profile()
    plan.save()
    form.save_m2m() # if neccesary

由于ModelChoiceField继承自ChoiceFIeld,因此您应该为此使用小部件:

类平面图(forms.ModelForm):
所有者=forms.ModelChoiceField(
queryset=Profile.objects.all(),
widget=forms.MultipleHiddenInput())
类元:
模型=计划

设置表单时,如何设置所有者的值。我们能看到吗?这是一个有趣的方法。在这种情况下,这对我来说是不合适的,因为计划在概念上并不“低于”所有者配置文件(我可能有很多其他相关对象),但我可以看到它在某些情况下起作用。这也是我自己喜欢使用的方法。同样,URLConf可以是(r'^plan/create',view.plan.create),并将概要文件和/或其他计划信息作为GET传递。您的视图检查GET参数,并用它们预填充表单。计划创建仍然是幂等的,因为GET请求实际上并不创建新的计划,只需为表单种子。好的。。。这很有帮助。奇怪的是,在创建表单时必须显式使用.pk,但在读取+1时不能重新引用。POST数据很容易调整。但是,既然我们可以引用用户,为什么还要引用配置文件呢?