0

So I have a formset which i use to build a basic html table where I can dynamically add forms to the table as a row.

The problem I'm having is that when I post my data and run my is_valid() on my formset, i keep getting the 'unicode' object has no attribute 'get' exception

Form:

class ModbusRegistersForm(ModelForm):
    ixRegisterType = ModelChoiceField(queryset=RegisterType.objects.all()),
    class Meta:
        model = Register
        fields = ['sRegisterName','iStartingAddr','iEndingAddr','ixRegisterType','iOffset']
        widgets = {
                'sRegisterName': TextInput(attrs={'placeholder': 'Register Name','class': 'form-control', 'data-form': '0'}),
                'iStartingAddr': TextInput(attrs={'placeholder': 'Starting address','class': 'form-control','data-form': '0'}),
                'iEndingAddr': TextInput(attrs={'placeholder': 'Ending address','class': 'form-control','data-form': '0'}),
                'iOffset': TextInput(attrs={'placeholder': 'Address offset','class': 'form-control','data-form': '0'}),
            }

View:

def create_modbus_view(request):
    assert isinstance(request, HttpRequest)


    modbus_device = CreateModbusForm()
    RegisterFormset = modelformset_factory(Register, form=ModbusRegistersForm)
    register_forms = RegisterFormset()

    return render(
        request,
        'app/create_modbus.html',
        context_instance = RequestContext(request,
        {
            'title':'Create Modbus Device',
            'tag': 'create_modbus',
            'modbus_device': modbus_device,
            'register_forms': register_forms
        })
    )

Ajax view receiving the POST:

def ping_device(request):
    response_data = {}
    response_data['conn_result'] = '' 

    try:
        if request.method == 'POST':
            port = None
            slave = None
            ip = None

            modbus_device = CreateModbusForm(request.POST['form'])

            RegisterFormset = modelformset_factory(Register, form=ModbusRegistersForm)
            registers = RegisterFormset(request.POST['form'])

            if registers.is_valid(): #fails here
                for reg in registers.forms:
                    hi = "i never work"

            if modbus_device.is_valid():
                port = modbus_device['port']
                slave = modbus_device['slave_id']
                ip = modbus_device['ip_address']

                registers = modbus_device


            response_data['conn_result'] = mb_ping_result

            return JsonResponse(response_data)

    except Exception as e:
        response_data['conn_result'] = str(e)
        return JsonResponse(response_data)

EDIT seems my registers formset doesn't contain a forms attribute , also my stack trace:

    Internal Server Error: /ping_device
Traceback (most recent call last):
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\core\handlers\base.py", line 132, in get_res
ponse
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\app\views.py", line 128, in ping_device
    for reg in registers.forms:
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\utils\functional.py", line 60, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\forms\formsets.py", line 142, in forms
    forms = [self._construct_form(i) for i in range(self.total_form_count())]
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\forms\formsets.py", line 115, in total_form_
count
    return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolut
e_max)
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\forms\formsets.py", line 94, in management_f
orm
    if not form.is_valid():
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\forms\forms.py", line 184, in is_valid
    return self.is_bound and not self.errors
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\forms\forms.py", line 176, in errors
    self.full_clean()
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\forms\forms.py", line 392, in full_clean
    self._clean_fields()
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\forms\forms.py", line 401, in _clean_fields
    value = field.widget.value_from_datadict(self.data, self.files, self.add_pre
fix(name))
  File "C:\Users\jb.DOM\Desktop\BACnet Modbus\ModbusBACnet\BACnetModbus_
WebApp\env\lib\site-packages\django\forms\widgets.py", line 223, in value_from_d
atadict
    return data.get(name, None)
AttributeError: 'unicode' object has no attribute 'get'
[15/Sep/2015 17:20:14] "POST /ping_device HTTP/1.1" 500 17336

EDIT 2 request.POST['form'] content:

HTTP/1.1" 200 16448
device_name=dev&csrfmiddlewaretoken=UrsGnQNnpEGVptIGXlEe2221AfdAzRv9&port=3&slav
e_id=3&ip_address=3&form-TOTAL_FORMS=2&form-INITIAL_FORMS=0&form-MIN_NUM_FORMS=0
&form-MAX_NUM_FORMS=1000&form-0-sRegisterName=est&form-0-iStartingAddr=5&form-0-
iEndingAddr=34&form-0-ixRegisterType=1&form-0-iOffset=1&form-1-sRegisterName=tes
t&form-1-iStartingAddr=5&form-1-iEndingAddr=34&form-1-ixRegisterType=1&form-1-iO
ffset=1
john
  • 3,949
  • 7
  • 34
  • 56
  • 1
    Don't know if helps, but seems similar to [this question](http://stackoverflow.com/questions/27326638/attributeerror-unicode-object-has-no-attribute-get-in-django-forms). Hope it helps. – jlnabais Sep 15 '15 at 20:41
  • thanks, I'll take a look – john Sep 15 '15 at 20:47
  • can you paste your exact stack trace ? Also, make sure you do not have a local variable with the conflicting name. Also, i think `registers = RegisterFormset(request.POST['form'])` should be `registers = RegisterFormset(request.POST)` – karthikr Sep 15 '15 at 21:15
  • the reason I do `request.POST['form']` is because my ajax call serializes the form as 'form' for a key so to actually access the form I have to do that – john Sep 15 '15 at 21:19
  • You still need to post the full traceback. – Daniel Roseman Sep 15 '15 at 21:21
  • yeah, was just formatting it, posted it now – john Sep 15 '15 at 21:23
  • Can you show what the actual content of request.POST['form'] is? This looks like a rather specialized use case, so you may have to manually instantiate a QueryDict to pass to your form. If you're really lucky, you can just do `RegisterFormset(QueryDict(request.POST['form']))`. – Joey Wilhelm Sep 15 '15 at 22:53
  • added my form content – john Sep 16 '15 at 13:33

1 Answers1

0

Thanks to jlnabaisfor the post link, I did look at that answer before but didn't understand it fully, so when you posted it I went back and figured it out.

Since I was using ajax, the post data was converted to a unicode string so when I was trying to access the data, it couldn't parse the string. If I did this without ajax then it works. Since I'm sticking to ajax, I used urlparse and QueryDict to parse the unicode data and convert it to a dictionary.

RegisterFormset = modelformset_factory(Register, form=ModbusRegistersForm)

        if request.method == 'POST':

            my_dic = dict(urlparse.parse_qsl(request.POST['form']))    

            modbus_device = CreateModbusForm(my_dic)

            if modbus_device.is_valid():
                port = modbus_device.cleaned_data['iPort']
                slave = modbus_device.cleaned_data['iSlave']
                ip = modbus_device.cleaned_data['sIP']
            else:
                raise ValueError(modbus_device.errors)

            registers = RegisterFormset(QueryDict(request.POST['form']))
            for reg in registers.forms:
                if reg.is_valid():
                    container = RegisterContainer()
                    container.reg_name = reg.cleaned_data['sRegisterName']
                    container.reg_start_addr = reg.cleaned_data['iStartingAddr']
                    container.reg_range = reg.cleaned_data['bRange']
                    container.reg_type = reg.cleaned_data['ixRegisterType'].ixRegisterType
                    container.reg_offset = reg.cleaned_data['iOffset']

                    register_list.append(container)
                else:
                    raise ValueError(registers.errors)
john
  • 3,949
  • 7
  • 34
  • 56