Как сделать так, чтобы экземпляр внутри формы Django принимал несколько значений?

Я делаю Django блог и хочу, чтобы пользователь мог редактировать свой пост. У меня есть 2 формы для редактирования, Post Form, которая включает (заголовок, изображение поста, содержание, категория) и другая отдельная форма для тегов поста, которая включает (имя тега). Для редактирования тегов я должен получить все теги, связанные с постом, и установить их в атрибут instance, который принимает только один объект (а у меня несколько тегов для одного поста). Вот мои модели:

class PostTags(models.Model):
    tag_name = models.CharField(max_length=100)

    def __str__(self):
        return self.tag_name

class Post(models.Model):
    title = models.CharField(max_length=50)
    picture = models.ImageField(null=True,upload_to='images/')
    content = models.CharField(max_length=255)
    likes = models.ManyToManyField(User,blank=True,related_name='likes')
    dislikes = models.ManyToManyField(User,blank=True,related_name='dislikes')
    date_of_publish = models.DateTimeField(auto_now_add=True,null=True,blank=True)
    user = models.ForeignKey(User,on_delete=models.CASCADE)
    category = models.ForeignKey(Category,on_delete=models.CASCADE)
    tag = models.ManyToManyField(PostTags,blank=True)
      
    def __str__(self):
        return self.title

Вот мои формы:

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title','picture','content','category']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'picture': forms.FileInput(attrs={'class': 'form-control'}),
            'content':forms.TextInput(attrs={'class': 'form-control'}),
            'category' : forms.Select(attrs={'class':'form-control'}),
        }

class TagsForm(forms.ModelForm):
    class Meta:
        model = PostTags
        fields = ['tag_name']
        widgets = {
            'tag_name': forms.TextInput(attrs={'class': 'form-control', 'data-role': 'tagsinput'})
        }

и вот моя попытка получить все теги в форме тегов в views.py

def editPost(request,post_id):
    post = Post.objects.get(id= post_id)
    post_form = PostForm(instance=post)
    # tagInstance = []
    for tag in post.tag.all():
        print(tag)
        newTag = PostTags.objects.get(tag_name=tag)
        tag_form = TagsForm(instance=newTag)
        # tagInstance.append(newTag)
 
    # print(tagInstance)
    
    
    # if request.method == 'POST':
    #     form = PostForm(request.POST,instance=post)
    #     if form.is_valid():
    #         form.save()
    #         return redirect('post')
    context = {"post_form":post_form,'tag_form':tag_form}
    return render (request,"dj_admin/editpost.html",context)

В результате вышеописанной попытки в форму тегов был выведен только последний тег, что и ожидалось

Если я правильно вас понял, вы хотите вывести все tag_forms, связанные с постом, внутри вашего шаблона.

Вы можете добиться желаемого, используя django model inline_formsets

forms.py:

from django.forms import inlineformset_factory
from .models import Post, PostTags

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title','picture','content','category']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'picture': forms.FileInput(attrs={'class': 'form-control'}),
            'content':forms.TextInput(attrs={'class': 'form-control'}),
            'category' : forms.Select(attrs={'class':'form-control'}),
        }

class TagsForm(forms.ModelForm):
    class Meta:
        model = PostTags
        fields = ['tag_name']
        widgets = {
            'tag_name': forms.TextInput(attrs={'class': 'form-control', 'data-role': 'tagsinput'})
        }

TagFormSet = inlineformset_factory(PostTags, Post, fields=('tag_name',))

views.py:

from .forms import PostForm, TagsForm, TagFormSet

def editPost(request,post_id):
    post = Post.objects.get(id= post_id)
    post_form = PostForm(instance=post)
    tag_formset = TagFormSet(instance=post)     
    
    if request.method == 'POST':
        form = PostForm(request.POST, instance=post)
        tag_formset = TagFormSet(request.POST, instance=post)
        if form.is_valid() and tag_formset.is_valid():
            form.save()
            tag_formset.save()
            return redirect('post')
    context = {'post_form': post_form, 'tag_formset': tag_formset}
    return render (request, 'dj_admin/editpost.html', context)

и затем внутри вашего файла шаблона вы можете просто добавить {{ tag_formset }} следующим образом:

<form method="post">
    {{ formset }}
</form>

Возможно, есть более чистое решение, но это должно работать:

def editPost(request,post_id):
    post = Post.objects.get(id= post_id)
    post_form = PostForm(instance=post)
    context = {}
    context['post_form'] = post_form
    count = 0
    for tag in post.tag.all():
        print(tag)
        newTag = PostTags.objects.get(tag_name=tag)
        tag_form = TagsForm(instance=newTag)
        count += 1
        context['tag_form'+str(count)] = TagsForm(instance=newTag)
    context['tag_form_counter'] = count
    return render (request,"dj_admin/editpost.html",context)

Итак, в вашем шаблоне вы должны проверить переменную tag_form_counter, чтобы знать, сколько у вас tag_forms. И сделать цикл forloop, чтобы показать их.

Вернуться на верх