一对一选择领域Django

时间:2019-06-06 08:21:22

标签: python django

所以我有一个工厂模型和一个传感器模型。它们之间是一对一的关系。当我要添加新植物时,我希望表单仅向我显示“未使用”的传感器作为选择(那些尚未与植物建立关系的传感器)。我已经尝试了多种方法,但是我不知道如何使它起作用

我已经尝试通过检查所有传感器并将未使用的传感器添加到CHOICE元组中来向AddPlant表单添加功能。之后,我添加了一个带有ChoiceICE元组作为选择的传感器ChoiceField。它可以正常工作,但是每次我想向数据库中添加新传感器时,都必须保存forms.py文件,以查看将传感器添加到AddPlant表单中的“选择”中。

forms.py

 class AddPlant(forms.ModelForm):

    class Meta:
        model = Plant
        fields = (
                'name',
                'photo',
                'type_plant',
            )

    def __init__(self,CHOICES, *args, **kwargs):
        super(AddPlant, self).__init__(*args, **kwargs)
        self.fields['sensor'] = forms.ChoiceField(choices=CHOICES)

models.py

class Sensor(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Plant(models.Model):
    name = models.CharField(max_length=13)
    photo = models.ImageField(upload_to=get_image_path, blank=True, null=True)
    sensor = models.OneToOneField(Sensor, on_delete=models.DO_NOTHING, null=True, blank=False,)
    type_plant = models.ForeignKey('TypePlant', on_delete=models.DO_NOTHING)
    status = models.IntegerField(null=True)

    def __str__(self):
        return self.name

views.py

@login_required
def add_plant(request):

    if len(Plant.objects.all()) >= len(Sensor.objects.all()):

        return redirect('/account/add_plant/error_add_sensor')

    CHOICES = ()
    used_sensors = []
    for plant in Plant.objects.all():
        used_sensors.append(plant.sensor)

    for sensor in Sensor.objects.all():
        if sensor not in used_sensors:
            CHOICES += ((sensor.name, sensor.name),)

    if request.method == 'POST':

        form = AddPlant(request.POST,request.FILES, CHOICES)

        if form.is_valid():
            plant = form.save()
            plant.photo = form.cleaned_data['photo']
            for sensor in Sensor.objects.all():
                if sensor.name == form.cleaned_data['sensor']:
                    plant.sensor = sensor
            plant.save()
            return redirect('/account/add_plant/confirmation')
        else:
            return redirect('account:error_add_plant')


    form = AddPlant(CHOICES)
    return render(request, 'account/add_plant.html', {'form': form})

带有以下代码的错误消息:

  

'tuple'对象没有属性'get'

代码在form.is_valid()处停止:

完整追溯:

AttributeError at /account/add_plant/
'tuple' object has no attribute 'get'
Request Method: POST
Request URL:    http://192.168.43.92:1234/account/add_plant/
Django Version: 2.2
Exception Type: AttributeError
Exception Value:    
'tuple' object has no attribute 'get'
Exception Location: /home/adam_suma/.local/lib/python3.6/site-packages/django/forms/widgets.py in value_from_datadict, line 385
Python Executable:  /usr/bin/python
Python Version: 3.6.7
Python Path:    
['/home/adam_suma/Lenautech',
 '/usr/lib/python36.zip',
 '/usr/lib/python3.6',
 '/usr/lib/python3.6/lib-dynload',
 '/home/adam_suma/.local/lib/python3.6/site-packages',
 '/usr/local/lib/python3.6/dist-packages',
 '/usr/lib/python3/dist-packages']
Server time:    Thu, 6 Jun 2019 08:29:54 +0000
Traceback Switch to copy-and-paste view
/home/adam_suma/.local/lib/python3.6/site-packages/django/core/handlers/exception.py in inner
            response = get_response(request) …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response
                response = self.process_exception_by_middleware(e, request) …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response
                response = wrapped_callback(request, *callback_args, **callback_kwargs) …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/contrib/auth/decorators.py in _wrapped_view
                return view_func(request, *args, **kwargs) …
▶ Local vars
/home/adam_suma/Lenautech/account/views.py in add_plant
        if form.is_valid(): …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/forms/forms.py in is_valid
        return self.is_bound and not self.errors …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/forms/forms.py in errors
            self.full_clean() …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/forms/forms.py in full_clean
        self._clean_fields() …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/forms/forms.py in _clean_fields
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/forms/widgets.py in value_from_datadict
        upload = super().value_from_datadict(data, files, name) …
▶ Local vars
/home/adam_suma/.local/lib/python3.6/site-packages/django/forms/widgets.py in value_from_datadict
        return files.get(name) …
▶ Local vars
Request information
USER
admin

1 个答案:

答案 0 :(得分:0)

您已经通过将CHOICES作为第一个位置参数来更改了表单init方法的签名。这意味着默认参数-数据和文件-现在应该在选择之后 ,而不是之前。发生错误是因为您选择的元组被用作数据参数。

真的,您应该避免这样更改签名。您应该从kwarg中获得选择,将其作为关键字而不是按位置传递。同样,您不应该对参数名称使用全大写;那是常量。

所以:

def __init__(self, *args, **kwargs):
    choices = kwargs.pop('choices', [])
    super(AddPlant, self).__init__(*args, **kwargs)
    self.fields['sensor'] = forms.ChoiceField(choices=choices)

并在视图中:

form = AddPlant(request.POST, request.FILES, choices=CHOICES)

但是请注意,所有这些似乎都没有必要。对于从其他模型中进行选择的字段,请使用ModelChoiceField。您希望选择所有未使用的传感器,因此只需将其设置为queryset即可;完全不需要覆盖__init__,也不需要视图中所有复杂的逻辑。

class AddPlant(forms.ModelForm):

    sensor = forms.ModelChoiceField(queryset=Sensor.objects.filter(plant=None))

    class Meta:
        model = Plant
        fields = (
                'name',
                'photo',
                'type_plant',
                'sensor'
            )

还请注意,但是,您要做的 必须在字段列表中具有“传感器”,否则将不会被保存。