Один на Один Выбор Поле Джанго - PullRequest
0 голосов
/ 06 июня 2019

Итак, у меня есть модель завода и модель датчика.Между ними - один-на-один.Когда я хочу добавить новый завод, я хочу, чтобы форма показала мне только «неиспользуемые» датчики в качестве выбора (тех, кто еще не имеет отношения к растению).Я пробовал несколько способов, но я не могу понять, как заставить его работать

Я пытался добавить функциональность в форму AddPlant, проверив все датчики и добавив неиспользуемые в кортеж CHOICE.После этого я добавил датчик ChoiceField с набором CHOICE в качестве выбора.Это работало, но каждый раз, когда я хотел добавить новый датчик в базу данных, мне приходилось сохранять файл 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'

Код останавливается на if 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 голосов
/ 06 июня 2019

Вы изменили сигнатуру метода init формы, указав CHOICES в качестве первого позиционного аргумента. Это означает, что аргументы по умолчанию - данные и файлы - теперь ожидаются после выбора, а не до. Ошибка происходит, потому что ваш кортеж выбора принимается в качестве аргумента данных.

На самом деле вам следует избегать изменения подписи таким образом. Вы должны получить выбор от kwargs, передавая его как ключевое слово, а не позиционно. Кроме того, вы не должны использовать все заглавные буквы для имен аргументов; это для констант.

Итак:

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'
            )

Также обратите внимание, что, как бы вы это ни делали, вам do необходимо иметь «датчик» в списке полей, иначе он не будет сохранен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...