views:

220

answers:

1

Hi!

I have a basic model :

class MyModel(models.Model):
    my_field = models.CharField()

I have a basic form for this model :

class MyFrom(forms.ModelForm):
    class Meta:
        model = MyModel

And I have a function that does a basic lookup (a lot more complex in reality, regex etc. won't do) :

POSSIBLE_VALUES = ['aa', 'bb', 'cc', 'dd']

def lookup(some_value):
    if some_value in POSSIBLE_VALUES:
        # the value is OK, return a string
        return some_value
    else:
        # constructs the 'did you mean' list of suggestions
        didyoumean = [pv for pv in POSSIBLE_VALUES if pv in some_value]
        # returns a list which might be empty
        return didyoumean

Now, the scenario that I want is:

  1. On the site I enter a value in the "my_field" input field and hit submit button.
  2. If the value passes the lookup I should automatically perform the form's action.
  3. If I get multiple possible values then I should display them to the user and no other action is performed.
  4. If I get no answers (an empty list) I should get an error message.

Some additional requirements:

  1. I would prefer the "did you mean" list to be displayed without having to reload the page.
  2. If a user clicks on one of the suggestions I want to perform the form's action without an additional lookup - the value has already been checked.
  3. I want to keep all the logic outside the view and keep it in the form or in the model. This is a must.
  4. I want to avoid hardcoded js in the template and push it into the form if possible. It's not a must.

So I assume that it would all be distributed between this fields validation and a custom widget that would handle the "did you mean" list rendering. I just can't put it all together.

Your help is required :)

EDIT. Ad. 2 in requirements. That is a basic feature I described. In a more advanced one I want this form to have more fields and so the "did you mean" list should be displayed along with all other fields errors (if any). Then clicking on a hint would just set the my_field's value to it's value without reloading the form. A user would have to correct other errors as well so I can't go to form's action right away. Might there be just some some flag to switch between those two options ("basic" and "advanced").

+2  A: 
  1. I would prefer the "did you mean" list to be displayed without having to reload the page.

Create custom widget, which renders with JS code for checking possible values as user enters it

  1. If a user clicks on one of the suggestions I want to perform the form's action without an additional lookup - the value has already been checked.

Again, that widget, when clicked, should just submit the form.

  1. I want to keep all the logic outside the view and keep it in the form or in the model. This is a must.

On the form you'll have clean() method to validate everything. If, say, some bogus data passes with submit from p. 2 - you still raise validation error.

  1. I want to avoid hardcoded js in the template and push it into the form if possible. It's not a must.

Solved with custom widget, details.

Dmitry Shevchenko
Hey, I've been working on this for last couple of days and I got it working. Some parts are ugly because I wanted to make this method reusable thus needed to dynamically generate things - like passing a value from a view to the form (while creating) so that it gets to the widget's rendering method.I've modified a bit my requirements but generally this is the was I did it (using jQuery):1. Clicking on a submit button sends the form (serialized) to the ajax handling view.2. If the form validates then I send back an empty value and if it doesn't validate then I send back the rendered form.
virtuallight
3. When the answer get's back to the js:- if empty then the form is submited and finally properly handled- if not empty (the form with errors and hints is there) I just cover the old form with it4. Clicking on a hint puts it's value in the input field and the form get's validated via ajax again.Thx for the answer. It convinced me that digging in the widget is the right choice ;)
virtuallight