【问题标题】:Save a django object getting another model instance as foreign key from a form保存从表单获取另一个模型实例作为外键的 django 对象
【发布时间】:2012-12-26 11:39:33
【问题描述】:

我一直在尝试保存一个模型实例,该实例从一个表单中获取另一个模型的实例作为外键。

型号

class Customer(models.Model):
    owner = models.ForeignKey(User)
    custname = models.CharField() 

class Appointment(models.Model):
    user = models.ForeignKey(User)
    start = models.DateTimeField()
    end = models.DateTimeField()
    customer = models.ForeignKey(Customer)

表格

class AppointmentForm(forms.Form):
    basedate = forms.DateField()
    start = forms.TimeField(widget=forms.Select())
    end = forms.IntegerField(widget=forms.Select())
    customer = forms.ModelMultipleChoiceField(queryset=Customer.objects.all())

我无法在通用 FormView 中使用的方法:

def form_valid(self, form):
    if form.is_valid():
        appointment = Appointment()
        appointment.user = self.request.user
        basedate = form.cleaned_data['basedate']
        start = form.cleaned_data['start']
        duration = form.cleaned_data['end']
        appointment.start = datetime.datetime.combine(basedate, start)
        appointment.end = appointment.start + datetime.timedelta(minutes=duration)
        appointment.save()
        return super(AppointmentCreate, self).form_valid(form)

我应该在最后一个方法中添加什么来从表单中读取外键客户,然后将其传递给约会?是否有任何过滤方式,以便在表单中只出现属于 request.user 的客户?

非常感谢您的帮助。

【问题讨论】:

    标签: django forms foreign-keys


    【解决方案1】:

    这样的事情应该可以工作。有几点:

    1) 我将表单字段更改为 ModelChoiceField 而不是多项选择。您需要使用 ModelChoiceField 来显示关系。我从 MultipleChoice 更改了它,因为根据您的模型,您只想保存一个选择。您可以在此处阅读有关 ModelChoiceFields 的更多信息:https://docs.djangoproject.com/en/dev/ref/forms/fields/

    2) 在您的表单中,我将选择查询更改为customer = forms.ModelChoiceField(queryset=Customer.objects.filter(owner=request.user)。这将仅过滤特定用户的客户。

    forms.py

    class AppointmentForm(forms.Form):
        def __init__(self, *args, **kwargs):
            self.request = kwargs.pop("request")
            super(AppointmentForm, self).__init__(*args, **kwargs)
    
        basedate = forms.DateField()
        start = forms.TimeField(widget=forms.Select())
        end = forms.IntegerField(widget=forms.Select())
        customer = forms.ModelChoiceField(queryset=Customer.objects.filter(owner=request.user))
    

    views.py

    def form_valid(self, form):
        if request.method=='POST':
            form = AppointmentForm(request.POST, request=request)
            if form.is_valid():
                appointment = Appointment()
                appointment.user = self.request.user
                basedate = form.cleaned_data['basedate']
                start = form.cleaned_data['start']
                duration = form.cleaned_data['end']
                appointment.customer = form.cleaned_data['customer']
                appointment.start = datetime.datetime.combine(basedate, start)
                appointment.end = appointment.start + datetime.timedelta(minutes=duration)       
                appointment.save()
                return super(AppointmentCreate, self).form_valid(form)
        else:
            form = AppointmentForm()
    

    【讨论】:

    • 现在我可以保存 Appointment 的实例了,谢谢。但是有两个问题:在表单中,不允许使用 request.user 所以我不能为当前用户过滤客户。 ¿ 还有其他方法吗?而关于 ModelChoiceField,doc 说应该避免超过 100 种不同的选择。那么,这里最好的方法是什么?
    • 是什么阻止了您使用 request.user?如果您收到错误,请发布。至于 ModelChoiceField - 它是 Select 小部件,不推荐用于超过 100 种不同的选择,而不是字段本身。选择小部件是您将在表单 HTML 页面上使用以允许选择的小部件。有多种方法可以解决这个问题 - 修改选择小部件,使用 jQuery 选择小部件等。docs.djangoproject.com/en/dev/ref/forms/widgets
    • 了解选择小部件。关于表单问题,在尝试您的建议时,我得到:Exception Value: name 'request' is not defined。我认为这样做的方法可能是覆盖表单类的'init'方法,但我无法使其工作。再次感谢您的帮助。
    • 我已编辑原始帖子以覆盖 init 以获取请求。此外,我已将request=request 添加到表单初始化中,因此 init 可以正常工作。不幸的是,我目前无法对其进行测试,但我认为这应该对您有用。
    • 我已经尝试了您的建议,但我仍然收到 Exception Value: name 'request' is not defined. 表单。
    【解决方案2】:

    我终于做到了。关键是要覆盖views.py中FormView类的get方法,而不是修改forms.py中的init

    forms.py:

    class AppointmentForm(forms.Form):
        basedate = forms.DateField()
        start = forms.TimeField(widget=forms.Select())
        end = forms.IntegerField(widget=forms.Select())
        customer = forms.ModelChoiceField(queryset=Customer.objects.all())
        ...
    

    views.py:

        def get(self, request, *args, **kwargs):
            """
            Handles GET requests and instantiates a blank version of the form.
            """
            choices_start, choices_duration = self._get_choices()
            form_class = self.get_form_class()
            form = self.get_form(form_class)
            form.fields['start'].widget=forms.Select(choices=choices_start)
            form.fields['end'].widget=forms.Select(choices=choices_duration)
            form.fields['customer'].queryset=Customer.objects.filter(owner=request.user)
            return self.render_to_response(self.get_context_data(form=form))
    

    @Dan:非常感谢您为我提供的帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-21
      • 2021-03-08
      • 2011-04-27
      • 2013-12-28
      • 2015-02-27
      • 2020-06-17
      相关资源
      最近更新 更多