Django m2m как использовать name вместо name_id

#django #python-3.x #bootstrap-tags-input

#django #python-3.x #bootstrap-теги-ввод

Вопрос:

я хочу добавить теги для новых сообщений. Я использую ввод тегов bootstrap. Это работает, только если я пишу tags_id, а не заголовок тега. И если я напишу новые числа, это сохранит сообщение с новым тегом number.

Как изменить tag_id на tag_title в таблице m2m db или другим способом это исправить?

Модели

 class Tag(models.Model):
    title = models.CharField(max_length=50)
    slug = models.SlugField(max_length=50, unique=True)

class Post(models.Model):
    title = models.CharField(max_length=150, db_index=True)
    slug = models.SlugField(max_length=150, blank=True, unique=True)
    body = RichTextField()
    date_pub = models.DateTimeField(auto_now_add=True)
    tags = models.ManyToManyField(Tag, blank=True, related_name='posts')
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    views = models.IntegerField(blank=True, default=0)
  

число просмотров

 def post(self, request):
    tags = request.POST.getlist('tags')
    for tag in tags:
        objs, created = Tag.objects.get_or_create(title=tag, slug=tag)
    bound_form = self.model_form(request.POST))
    if bound_form.is_valid():
        post = bound_form.save(commit=False)
        post.author = request.user
        post.save()
        post.tags.add(objs)
        post.save()

        new_obj = bound_form.save()
        return redirect(new_obj)
    return render(request, self.template, context={'form': bound_form})
  

форма

 class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'slug', 'body', 'tags']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'slug': forms.TextInput(attrs={'class': 'form-control'}),
            'body': forms.Textarea(attrs={'class': 'form-control'}),
            'tags': forms.SelectMultiple(attrs={'class': 'form-control', 'data-role': 'tagsinput'}),

        }
        exclude = ['author',]
  

Я хочу, чтобы теги были словами, а не идентификаторами. Теперь, когда я добавляю слова, отображается ошибка:
«qwe» не является допустимым значением.
Ему нужны числа и, возможно, исправить отображение всех тегов в select.
введите описание изображения здесь

Комментарии:

1. Ваш вопрос немного запутанный, не могли бы вы пояснить, что вы подразумеваете под «tag_id» и «tag_title»?

2. Существует связь между post и тегом в post_tags. он создается с помощью идентификатора многие ко многим post_id tag_id

3. Поскольку title не определен как уникальный, вы не можете использовать title напрямую. Вы должны определить свое собственное поле формы, которое принимает список тегов в качестве входных данных, и обработать этот список самостоятельно, извлекая соответствующие теги и добавляя их к вашим отношениям m2m. Также вы, вероятно, захотите решить, что делать с прописными / строчными буквами, похожими тегами (одно слово / два слова), когда создавать новые теги и т.д… Для отображения переопределите __str__() метод в вашей Tag модели или переопределите поле формы и его label_from_instance() метод.

4. тег slug уникален. и title=slug. или title тоже должен быть уникальным

5. То есть пользователь может выбирать только из существующих тегов? Или он может добавить новые? Это имеет большое значение здесь.

Ответ №1:

То, как определена ваша модель, вы не можете использовать title в качестве уникального идентификатора для вашего тега. Также, если вы позволяете пользователям создавать новые теги, вы, вероятно, захотите принять во внимание, что «виндсерфинг», «Windsurfing» и «wIndsurfing» — это одно и то же.

Также, поскольку вы хотите, чтобы пользователи могли добавлять новые теги, вы не можете использовать идентификаторы тегов в своей форме, поскольку у новых тегов еще нет идентификатора (это сработало бы, только если бы вы разрешали пользователям выбирать из существующих тегов).

Итак, ваша HTML-форма должна опубликовать список строк в форме Django. И в вашей форме вам нужно обработать эти строки для сохранения в виде тегов:

  • В вашем PostForm добавьте поле tags в качестве TextInput field. Это тот, который вы будете отображать в качестве входных тегов bootstrap в вашей HTML-форме.
  • Удалите 'tags' из списка fields в вашей форме модели.
  • Переопределите __init__() метод PostForm , чтобы установить начальные значения tags в виде списка заголовков, разделенных запятыми: self.fields['tags'].initial = ",".join([tag.title for tag in self.instance.tags.all()])
  • Переопределите clean_tags() метод, чтобы убедиться, что входные данные представляют собой список строк, разделенных запятыми, возможно, изменив их все на строчные.
  • Переопределите save() метод для обработки тегов:
 def save(commit=True):
    post = super().save(commit=commit)
    if commit:  # only save new tags if commit == True
        tags_titles = self.cleaned_data['tags'].split(",")
        for title in tags_titles:
            tag = Tag.objects.get_or_create(title=title.lower())  # assuming slug is auto-created when saving and all titles are saved lowercase
            post.tags.add(tag)
    return post
  

Итак, в основном ваши формы просто обрабатывают строку (список строк, разделенных запятыми), которые являются заголовками ваших тегов. И ваша форма Django преобразует это обратно в реальные Tag объекты.

Комментарии:

1. у меня получилось с: 1. self.initial['tags'] = ",".join([tag.title for tag in self.instance.tags.all()]) 2. не удалять из полей 3. widgets = { 'tags': TextInput(attrs={'size': '100'}), }