簡體   English   中英

一對一選擇領域Django

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM