开发者

Django repeating vars/cache issue?

开发者 https://www.devze.com 2022-12-25 22:59 出处:网络
I\'m trying to build a better/more powerful form class for Django. It\'s working well, except for these sub-forms. Actually, it works perfectly right after I re-start apache, but after I refresh the p

I'm trying to build a better/more powerful form class for Django. It's working well, except for these sub-forms. Actually, it works perfectly right after I re-start apache, but after I refresh the page a few times, my HTML output starts to look like this:

<input class="text" type="text" id="pickup_addr-pickup_addr-pickup_addr-id-pickup_addr-venue" value="" name="pickup_addr-pickup_addr-pickup_addr-pickup_addr-venue" />

The pickup_addr- part starts repeating many times. I was looking for loops around the prefix code that might have cause this to happen, but the output isn't even consistent when I refresh the page, so I think something is getting cached somewhere, but I can't even imagine how that's possible. The prefix var should be reset when the class is initialized, no? Unless it's somehow not initializing something?

class Form(object):
    count = 0
    def __init__(self, data={}, prefix='', action='', id=None, multiple=False):
        self.fields = {}
        self.subforms = {}
        self.data = {}
        self.action = action
        self.id = fnn(id, 'form%d' % Form.count)
        self.errors = []
        self.valid = True
        if not empty(prefix) and prefix[-1:] not in ('-','_'): prefix += '-'

        for name, field in inspect.getmembers(self, lambda m: isinstance(m, Field)):
开发者_开发问答            if name[:2] == '__': continue
            field_name = fnn(field.name, name)
            field.label = fnn(field.label, humanize(field_name))
            field.name = field.widget.name = prefix + field_name + ife(multiple, '[]')
            field.id = field.auto_id = field.widget.id = ife(field.id==None, 'id-') + prefix + fnn(field.id, field_name) + ife(multiple, Form.count)
            field.errors = []

            val = fnn(field.widget.get_value(data), field.default)

            if isinstance(val, basestring):
                try:
                    val = field.coerce(field.format(val))
                except Exception, err:
                    self.valid = False
                    field.errors.append(escape_html(err))

            field.val = self.data[name] = field.widget.val = val

            for rule in field.rules:
                rule.fields = self.fields
                rule.val = field.val
                rule.name = field.name

            self.fields[name] = field

        for name, form in inspect.getmembers(self, lambda m: ispropersubclass(m, Form)):
            if name[:2] == '__': continue
            self.subforms[name] = self.__dict__[name] = form(data=data, prefix='%s%s-' % (prefix, name))

        Form.count += 1  

Let me know if you need more code... I know it's a lot, but I just can't figure out what's causing this! I'm not even using any cache middleware.


Copying/cloning the fields first gives me this output instead:

<label for="None">None</label>
<input class="text" type="text" id="id-pickup_address-venue" value="" name="pickup_address-venue" />

field.name and field.label are set in exactly the same way... in fact, field.id is correctly displayed on the <input> but that same value is suddenly gone when I try to print the label.... the difference is that the <input> bit is printed by the Widget class, whereas the label is printed directly from my template... which I guess is.... oh I get it, that one is still referring to the unset class-level/static field, rather than the instance field...


You're probably declaring your forms like this:

class SomeForm(Form):
    someField = Field(....)
    ...

Now, this means that one instance of someField will actually be shared among all your SomeForm instances. In your __init__ you're changing the attributes of the field, which will affect all forms, not just the current one, including ones created in the future.

To fix this, you can make a copy of the field for each instance:

field = copy(field)  #maybe you need deepcopy instead
setattr(self, name, field)   

And then change the attributes of the copy.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号