0

What I'm trying to do

I'm trying to enter a list of tags in flask that should become passable as a list but I can't figure out how to do it in flask, nor can I find documentation to add lists (of strings) in flask_wtf. Has anyone have experience with this?

Ideally I would like the tags to be selectively delete-able, after you entered them. So that you could enter.

The problem

Thus far my form is static. You enter stuff, hit submit, it gets processed into a .json. The tags list is the last element I can't figure out. I don't even know if flask can do this.

A little demo of how I envisioned the entry process:

How I envisioned the entry process:

  1. The current tags are displayed and an entry field to add new ones.
    [Tag1](x) | [Tag2](x)

    Enter new Tag: [______] (add)
  1. Hit (add)
    [Tag1](x) | [Tag2](x)

    Enter new Tag: [Tag3__]  (add)
  1. New Tag is added
    [Tag1](x) | [Tag2](x) | [Tag3](x) 

    Enter new Tag: [______]

How I envisioned the deletion process:

  1. Hitting the (x) on the side of the tag should kill it.
    [Tag1](x) | [Tag2](x) | [Tag3](x) 
  1. Hit (x) on Tag2. Result:
    [Tag1](x) | [Tag3](x)

The deletion is kind of icing on the cake and could probably be done, once I have a list I can edit, but getting there seems quite hard. I'm at a loss here.

I basically want to know if it's possible to enter lists in general, since there does not seem to be documentation on the topic.

blkpingu
  • 1,556
  • 1
  • 18
  • 41
  • Flask works on backed only. You could use JavaScript for your stuff. Eg. jQuery is good choice. – Debendra Feb 15 '19 at 19:21
  • @Debendra can you specify for what part / elaborate / write an answer? I'm genuinely interested in what you mean. I don't see how JavaScript can give me a python list object with `flask_wtf`. Also, I don't intend on using a database. My form is only supposed to generate a `.json` object. And since `.json` can have lists, I need this. – blkpingu Feb 15 '19 at 19:24
  • https://stackoverflow.com/questions/8963693/how-to-create-json-string-in-javascript would help you – Debendra Feb 15 '19 at 19:26
  • @Debendra To come back to the topic: You're saying, entering lists with WTForms is not possible? Can you quote a source and give me a reason why in an answer? I get a general gist of "just use javascript" from your comment. – blkpingu Feb 17 '19 at 17:57
  • Everything is possible but you have to invent your wheel on your own. Flask-wtform is just a thin wrapper of wtform. Currently there are no such way you could in wtform but you can use server side rendering technique to gather each tag which requires page reload on each add/delete. And in clients side rendering you can seamlessly gather each tag and save them at once. – Debendra Feb 17 '19 at 18:36

2 Answers2

1

Your description is not really clear (is Tag1 the key in the JSON or is it Tag the key, and 1 the index?)

But I had a similar issue recently, where I wanted to submit a basic list in JSON and let WTForms handle it properly.

For instance, this:

{
    "name": "John",
    "tags": ["code", "python", "flask", "wtforms"]
}

So, I had to rewrite the way FieldList works because WTForms, for some reason, wants a list as "tags-1=XXX,tags-2=xxx".

from wtforms import FieldList
class JSONFieldList(FieldList):
    def process(self, formdata, data=None):
        self.entries = []
        if data is None or not data:
            try:
                data = self.default()
            except TypeError:
                data = self.default

        self.object_data = data

        if formdata:
            for (index, obj_data) in enumerate(formdata.getlist(self.name)):
                self._add_entry(formdata, obj_data, index=index)
        else:
            for obj_data in data:
                self._add_entry(formdata, obj_data)

        while len(self.entries) < self.min_entries:
            self._add_entry(formdata)

    def _add_entry(self, formdata=None, data=None, index=None):
        assert not self.max_entries or len(self.entries) < self.max_entries, \
            'You cannot have more than max_entries entries in this FieldList'
        if index is None:
            index = self.last_index + 1
        self.last_index = index
        name = '%s-%d' % (self.short_name, index)
        id = '%s-%d' % (self.id, index)
        field = self.unbound_field.bind(form=None, name=name, id=id, prefix=self._prefix, _meta=self.meta,
                                        translations=self._translations)
        field.process(formdata, data)
        self.entries.append(field)
        return field

On Flask's end to handle the form:

from flask import request
from werkzeug.datastructures import ImmutableMultiDict

@app.route('/add', methods=['POST'])
def add():
    form = MyForm(ImmutableMultiDict(request.get_json())
    # process the form, form.tags.data is a list

And the form (notice the use of JSONFieldList):

class MonitorForm(BaseForm):
    name = StringField(validators=[validators.DataRequired(), validators.Length(min=3, max=5)], filters=[lambda x: x or None])
    tags = JSONFieldList(StringField(validators=[validators.DataRequired(), validators.Length(min=1, max=250)], filters=[lambda x: x or None]), validators=[Optional()])
blkpingu
  • 1,556
  • 1
  • 18
  • 41
Cyril N.
  • 38,875
  • 36
  • 142
  • 243
-1

I found a viable solution in this 2015 book, where a tagging system is being build for flask as part of a blog building exercise.

It's based on Flask_SQLAlchemy.

Entering lists therefore is possible with WTForms / Flask by submitting the items to the database via, e.g. FieldList and in the usecase of a tagging system, reading them from the database back to render them in the UI.

If however you don't want to deal with O'Rielly's paywall (I'm sorry, I can't post copyrighted material here) and all you want is a solution to add tags, check out taggle.js by Sean Coker. It's not flask, but javascript, but it does the job.

blkpingu
  • 1,556
  • 1
  • 18
  • 41
  • The article that links to is now unavailable. – Cyril N. Jun 18 '20 at 15:02
  • Yes of course, copy/pasting a paid content is not great. Unfortunately, the preferred method on StackOverflow is to have a direct answer of the question, not a link (as it can change or become invalid). – Cyril N. Jun 21 '20 at 16:01
  • You can delete though. Did so too. This discussion is out of place. – blkpingu Jun 21 '20 at 19:44