#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'}), }