0

I am using Python 2.7 and I have searched for a solution here, here and here but none of them did solve my problem I am working on a simple project (my first one) to practice CRUD using flask and a sqlite database with 2 tables:

  1. Categories
  2. Items

The problem is:

When i load the page the form is correctly displayed and when i select any category and submit, the form just gives me an error when calling

validate_on_submit()

says Not a valid choice with a return value of False

I defined the form like this:

from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SelectField
from wtforms.validators import DataRequired


class EditItemForm(FlaskForm):
    name = StringField(u'name', validators=[DataRequired()])
    description = TextAreaField("Description", validators=[
                                DataRequired()], render_kw={'rows': '7'})
    categories = SelectField(
        u'Categories', coerce=str, choices=[], validators=[DataRequired()])

    def set_choices(self, list_of_tuples=[]):
        self.categories.choices = list_of_tuples

and this is the function to edit an item:

@app.route('/category/<string:category_name>/<string:item_name>/edit/',
        methods=['GET', 'POST'])
def editItem(category_name, item_name):
    # get the category of the Item
    c = getCategory(category_name)

    # get the Item
    target_item = getItem(c, item_name)

    form = EditItemForm()

    # FIXME: Complete The process
    if request.method == 'POST':
        if form.validate_on_submit():
            # get selected category
            cat = dict(form.categories.choices).get(form.categories.data)
            targetCategory = getCategory(cat)

            # get identicals to avoid dublication
            identicals = getItemIdenticalsInCategory(
                targetCategory, form.name.data)

            if len(identicals >= 1):
                # FIXME: flash the Error in the same page
                return "An Item with the same name " + form.name.data + "     already exists in " + targetCategory.name

            else:
                # Edit The Item Data
                target_item.name = form.name.data
                target_item.description = form.description.data
                target_item.category_id = targetCategory.id

                # TODO: Flash the response
                return redirect(url_for('readCategoryItems',
                                        category_name=category_name))

        else:
            # display errors
            output = ""
            for fieldName, errorMessages in form.errors.items():
                for err in errorMessages:
                    # do something with your errorMessages for fieldName
                    output += fieldName + ":\t" + err + "<hr>"
            print(output)
            return output

    if request.method == 'GET':

        # Populate The form with current data
        form.name.data = target_item.name
        form.description.data = target_item.description
        cats = getAllCategories()
        list_of_tupels = []

        for cat in cats:
            session.refresh(cat)
            list_of_tupels.append((cat.name, cat.name))

        form.set_choices(list_of_tuples=list_of_tupels)

        return render_template('updateItem.html', 
            category_name=category_name,
                            item_name=item_name, form=form)

and this is the error output:

categories: Not a valid choice<hr>

edit: *this is what I got when I tried to debug it: Debug Variables Screenshot

  • why not just have the line `form.categories.choices = list_of_tupels` within the `if request.method == 'GET'` block. Don't put `choices=[]` in you model, as you're dyamically adding this. Have you printed out `list_of_tupels` along with the type of each in the tuple? – Andrew Allen Mar 13 '19 at 13:19
  • the type is 'unicode' for each element in each tuple of the list @AndrewAllen – Mohanad Shawky Mar 13 '19 at 14:00
  • this guy had similar issue..https://stackoverflow.com/questions/28718138/dynamic-selectfield-validation-fails-with-not-a-valid-choice – Andrew Allen Mar 13 '19 at 14:15
  • I don't know how to implement his solution but i managed to change the type to string by using type casting in my loop in the `GET` block but it did not solve the problem i think it is not about the type since it is not solved after changing it to `str` @AndrewAllen – Mohanad Shawky Mar 13 '19 at 14:45
  • apologies I wasn't neccessarily recommending his solution just that unicode seems likely to be the cause given that this post seems to match your error closely. Have you tried `encode` to ensure unicode gets converted to string? To check if error is unicode I would personally hard code a short example of what you think `list_of_tuples` should look like after your manipulations and see if this renders e.g `list_of_tuples = [('item1', 'item1'), ('item2', 'item2'), ('item3', 'item3')]`. There is also a Unicode sqlalchemy column type – Andrew Allen Mar 13 '19 at 15:40
  • i used this: `list_of_tupels.append( (str(cat.name).encode(), str(cat.name).encode()))` and printed them and every thing is exactly like what you said but the problem is not solved yet!!!! i think i should use a normal HTML Form it will be better and there is no chance for strange errors like this one! @AndrewAllen Thank you for your patience ^^ – Mohanad Shawky Mar 13 '19 at 16:17
  • if `string = 'pythön!'` on the console if I do `type(str(string).encode())` I get `` – Andrew Allen Mar 13 '19 at 16:35
  • I did the same and i got this `` and the result string was `'pyth?n!'` I used a normal HTML form and it worked for me maybe it is an issue or i have something wrong that i can't tell @AndrewAllen – Mohanad Shawky Mar 13 '19 at 16:48
  • have you debugged by breaking before the `validate_on_submit` and seeing what the form has supplied? and then if you expect it to validate or not? – Attack68 Mar 13 '19 at 22:12

0 Answers0