简体   繁体   中英

Django-taggit tag value retrieval and formatting failing

I am trying to implement a tagging process for profiles so you can add your hobbies for example. I have chosen django-taggit as it seemed quite simple and does what I need it to, plus don't really know how to do it myself from scratch. I have managed to make it work to some extent but I am having issues with 3 things:

  1. Not really sure what's the best way to control the form field for these tags as I generate the form automatically with widget adjustments in meta function of the form, but it might work fine after resolving the below two issues.
  2. When there is no data for the field hobbies (tags) the field gets populated with a single tag of value "[]" as per below image.

在此处输入图片说明

  1. When I add a tag of "music" and submit the form after I reload the page I get this "[]" as per image. I assumed this will be dealt with by the library, but I cannot see another similar scenario online.

在此处输入图片说明

When I try adding another tag of "games" and save and reload, the below happens. The initial value gets wrapped again.

在此处输入图片说明

My model is:

class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
hobbies = TaggableManager()

My form is:

class UserProfileForm(forms.ModelForm):

    class Meta:
        model = UserProfile
        fields = ['hobbies',]

    def __init__(self, *args, **kwargs):
      super(UserProfileForm, self).__init__(*args,**kwargs)
      self.fields['hobbies'].widget = forms.TextInput()
      self.fields['hobbies'].widget.attrs['data-role'] = "tagsinput"
      self.fields['hobbies'].widget.attrs['class'] = "form-control"
      self.fields['hobbies'].required = False

My view function is:

if request.method == 'POST':
        user_profile = UserProfile.objects.get(user=request.user)
        form = UserProfileForm(request.POST, instance=user_profile)
        print(form)
        if form.is_valid():
            obj = form.save(commit=False)
            obj.user = request.user
            obj.save()
            print("Form valid")
            form.save_m2m()

Using:

<script src="/static/js/tagsinput.js"></script>
<link rel="stylesheet" href="{% static 'css/tagsinput.css' %}" />

So after quite a few (hundreds) of tests, I finally narrowed down where the issue was and tried to go around it with successful result. It seems the data got amended into tag objects through tagsinput library I was using. Only when the "data-role" was specified as "tagsinput" in the forms.py the data would already come to html side as those objects and be shown incorrectly. So instead I wanted to keep the data clean and only apply data-role='tagsinput' in the end for visual aspect, which I did using:

var hobbiesTags = document.getElementById("id_hobbies");
  if(hobbiesTags){
  var att = document.createAttribute("data-role");
  att.value = "tagsinput";
  hobbiesTags.setAttributeNode(att);
  };

And that resulted in the below. Maybe there are better ways to do this, I'm not sure, but it's a pretty clean solution. Share your alternatives.

在此处输入图片说明

I had this exact same problem.

One solution is to apply the data-role="tagsinput" AFTER you turn a list of tags into a comma-separated string for the form.

Here is that solution:

class MyModelForm(forms.ModelForm):

    class Meta:
        model = MyModel

    def __init__(self, **kwargs):
        self.fields['tags'].widget.attrs['value'] = ", ".join(list(self.instance.tags.names()))
        self.fields['tags'].widget.attrs['data-role'] = "tagsinput"

Output:

腋窝报价

As you can see, there's a problem with quotes appearing around tags that are multi-word. It also causes new tags with quotes to be saved to the database.

引用的腋窝

If double-quotes didn't appear around multi-word phrases, this would be the most elegant solution. If someone solves this in the future, drop a note!

My template is this:

  <div class="m-3 p-3 border">
    <form method="POST" enctype="multipart/form-data">
      {% csrf_token %}
      {{ form|crispy }}
      <button class="btn btn-primary" type="submit">Save Form</button>
    </form>
  </div>

I know I can use a template tag to strip the extra quotes from the tag field itself, but then I'd have to go through and create all the form fields manually just to set the tags template tag.

For the time being, my solution is to simply use Javascript and just modify the Meta widgets section of the form.

FINAL ANSWER (for now):

forms.py

class CourseManageDetailsForm(forms.ModelForm):

    class Meta:
        model = MyModel

        widgets = {
            'tags': forms.TextInput(attrs={
                "data-role": "tagsinput",
            })
        }

custom.js - put this script on the page that loads the form.

document.addEventListener("DOMContentLoaded", function(event) {
    let tags_input = document.querySelector('#id_tags');
    let tags_input_value = tags_input.value;
    let new_value = [...tags_input_value.matchAll(/<Tag:\s*([\w\s]+)>/g)].map(([, m]) => m).join(', ')
    tags_input.setAttribute('value', new_value);
}

So all we're doing is modifying the front-end presentation, and leaving all the backend internal forms functionality untouched.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM