所以我有一个工厂模型和一个传感器模型。它们之间是一对一的关系。当我要添加新植物时,我希望表单仅向我显示“未使用”的传感器作为选择(那些尚未与植物建立关系的传感器)。我已经尝试了多种方法,但是我不知道如何使它起作用
我已经尝试通过检查所有传感器并将未使用的传感器添加到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
答案 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'
)
还请注意,但是,您要做的 必须在字段列表中具有“传感器”,否则将不会被保存。