Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restrict Creation of new Tags #7

Open
toabi opened this issue Nov 27, 2015 · 10 comments · May be fixed by #180
Open

Restrict Creation of new Tags #7

toabi opened this issue Nov 27, 2015 · 10 comments · May be fixed by #180

Comments

@toabi
Copy link

toabi commented Nov 27, 2015

I did not see an easy option to disallow the user to create new items, but only select existing ones.

@radiac
Copy link
Owner

radiac commented Nov 27, 2015

There's no way to stop people from adding tags at the moment, although it's an interesting idea, and one someone else asked for too.

What's your use case? If you just want the same visual effect but with hard-coded options, you'd probably be better off just using a charfield with a standard choices tuple, then use select2 directly to manage the drop-down - but I could certainly see a use for supporting permission-based tag creation, ie so only admins or certain users can add tags. I'll bear it in mind for a future version.

@toabi
Copy link
Author

toabi commented Nov 27, 2015

Yes, permission-based tag creation would be even better.

I'm looking for a nice way to categorise content, similar to https://github.com/callowayproject/django-categories – which isn't python3 compatible. Hardcoded select values are not an option because there are imports which have to create tags on the fly. But users should generally not allowed to create them.

Because this functionality will be used quite a bit, it's would be not very "DRY" to handcraft all the needed Models by hand. And other tagging solutions often don't properly support different "dictionaries" of tags.

@toabi toabi changed the title Restrict Creating of new Tags Restrict Creation of new Tags Nov 27, 2015
@torstenfeld
Copy link

I was just about to ask for the same / a similar feature. My use case is that I have a TagTreeModel with product/module combinations. For visualization and reporting topics, I like the TagTree feature to search for descendents, children, etc.
As the list of combinations is pretty static I wanted to restrict the creation of new tags as well.

@toabi
Copy link
Author

toabi commented May 17, 2017

@radiac I'm looking at tagging libraries again, is this feature now possible? :)

@SLiNv
Copy link

SLiNv commented Dec 13, 2017

Can we just in the frontend don't allow user to input but only search and select existing tags?

@calummackervoy
Copy link

I believe that this could be implemented by setting tags on the select2 to false (following some instruction on the user's form field), and then server-side by implementing validation on the form field which ensures the tag submitted exists?

I tested and for select2-3 createSearchChoice can return null

@calummackervoy calummackervoy linked a pull request May 4, 2023 that will close this issue
@calummackervoy
Copy link

calummackervoy commented May 4, 2023

I've opened a PR for the front-end aspect of this #180

Personally I think it should be OK to leave the validation of request data to the API developer - e.g. they might be using a serializer or the admin site instead of a form anyway:

Once merged then you can set a new tag option allow_create to tweak this behaviour in the form

In the meantime I've also found a workaround using jQuery (works only with version 3 but this issue might help getting it to work with v4):

$( document ).ready(() => {
    if($("#s2id_id_myfield").length) {
        $("#s2id_id_myfield").data("select2").opts.createSearchChoice = () => {return null}
    }
});

document.ready makes sure that it runs after tagulous has initialised the select2 component

@radiac
Copy link
Owner

radiac commented May 5, 2023

Thanks very much for your PR! It's always great to have contributions, and I really appreciate your effort.

Before I merge though, it would be good to get an idea of your use case. If a dev sets the flag in the tag options, do I understand the intent is to turn it into a multiple choice field for all users of the form?

I'm a bit worried about relying on js to enforce a rule like this - as a user my expectation would be that this flag would be trusted, set and forget; leaving the server-side enforcement as an exercise for the reader may be tricky, as from memory I don't think we offer much to help spot from a form or view which values are changing. It would also be easy for a dev to forget and not notice because they're using js. It feels like we're creating a potentially dangerous foot gun.

If I've understood the goal correctly, it may be safer to just use a MultipleChoiceField with a select2 widget.

Thinking out loud though, I wonder if some or most use cases for restricting a tag field would depend on who is seeing the field, not just which form it is in. That would need to be controlled from somewhere that has access to the request object - so most likely the form constructor. That would mean we'd need a way to manage different tagfield options on individual bound tag field, which I don't think we have at the moment.

This then ties into something mentioned earlier in the thread about permissions, which again may need to be handled with the request. I hadn't run into that specific use case myself, but over the past year or so I've noticed a similar missing feature - I want to be able to filter non-initial tags by a value or another field on the tagged model (a related object, limit tag visibility to those who created it, only list children of the currently-selected tag tree tag etc). Some relational queryset filtering could be done in the tag options without a request, but I suspect that wouldn't go far enough.

It feels like both of these issues could have a similar solution - possibly options in the form constructor, one to pass a filtered tag queryset, one to disable adding tags. It would be nicer to put the filter as a callable in the tag options, but I don't think the request can make it that far. I've been trying to resist it, but I think we need to introduce a tagfield-aware base form class, which is a whole new can of worms.

I'll give this all some more thought and see how it can fit together when I get back into the project code in the next few weeks - in particular how to manage the form and field classes, and whether we want to be able to customise some or all tag options on each request.

Thanks again!

@calummackervoy
Copy link

Hi! My use case is that I have a SingleTagField which should let users select from a dropdown of tags, but not to add their own. In the PR, if a dev sets the allow_create option to False, then the select2 component will have the correct properties set to prevent the creation of new tags (in both versions 3 and 4). When I tested locally I found that if I typed "existing tag" I was able to select the tag, but if I typed "non existing tag" then I had no options to select, where currently I would be given the option to select it anyway and create a new tag

I'm a bit worried about relying on js to enforce a rule like this

In my use case I wrote the view which accepts the form to strip the tag from the request if it doesn't already exist - I did this because it's a quick solution and the form validation code looked complex. I figured that the tag field could be getting created from a form, from the admin, from a serializer (DRF), mutation (GraphQL), the shell or otherwise in code - so backend protection would be happening in potentially many places depending on where the setting was applied. It was a convenient excuse not to provide it

It feels like we're creating a potentially dangerous foot gun.

I agree it would be better if the developer didn't have anything to do

If I've understood the goal correctly, it may be safer to just use a MultipleChoiceField with a select2 widget.

Looking at the Django docs for MultipleChoiceField very briefly, it looks like I'd need to get creative to allow for 1000+ tag options and the fact that the tags do still change in real-time (just not from this form I'm exposing to the user). With that in mind I prefer the workaround I posted before (adding JS to change the select2 component after the tagulous JS has run)

would depend on who is seeing the field, not just which form it is in

Good point. There may be a solution somewhere which allows for using a callable for the option allow_create (taking parameter request) and then in the form constructor binding the request to it

@sburlappp
Copy link

sburlappp commented Oct 10, 2024

I'm also interested in this feature, since my use case uses the tag UI to multi-select from a filtered subset of a very large table of valid choices, which only a few people can edit.

One approach would be to use something like: allow_create = lambda request : request.user.has_perm("app.add_mytagsclass")

Edit: I just realized that Django 5.0 presents exactly the UI I need on a normal ManyToManyField when the Admin form lists it in autocomplete_fields. I can either set that dynamically on the form based on has_perm, or set up a separate editing form with its own restrictions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants