![](/img/trans.png)
[英]Assigning Django model field within one model to point to one of a choice of other, related models
[英]One to One Choice Field Django
所以我有一個工廠模型和一個傳感器模型。 他們之間是一對一的關系。 當我想添加一個新的工廠時,我希望表單只顯示“未使用的”傳感器作為選擇(那些與工廠沒有關系的人)。 我嘗試了多種方法,但我無法弄清楚如何使其工作
我已經嘗試通過檢查所有傳感器並將未使用的傳感器添加到CHOICE元組中來向AddPlant表單添加功能。 之后我添加了一個帶有CHOICE元組的傳感器ChoiceField作為選擇。 它工作正常,但每次我想在數據庫中添加一個新的傳感器時,我必須保存forms.py文件以查看傳感器被添加到AddPlant表單中的Choices中。
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
您已通過將CHOICES作為第一個位置參數來更改表單的init方法的簽名。 這意味着默認的args - 數據和文件 - 現在預計會在選擇之后出現,而不是之前。 發生錯誤是因為您的選擇元組被視為數據參數。
真的,你應該避免改變這樣的簽名。 您應該從kwargs中獲取選擇,將其作為關鍵字而不是位置傳遞。 此外,您不應該將all-caps用於參數名稱; 這是常數。
所以:
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。 您希望選擇是所有未使用的傳感器,因此只需將其設置為查詢集; 根本不需要覆蓋__init__
,也不需要視圖中的所有復雜邏輯。
class AddPlant(forms.ModelForm):
sensor = forms.ModelChoiceField(queryset=Sensor.objects.filter(plant=None))
class Meta:
model = Plant
fields = (
'name',
'photo',
'type_plant',
'sensor'
)
另外請注意,但是你這樣做,你就必須在字段列表“傳感器”,否則它不會被保存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.