thebot
thebot

Reputation: 249

Associating a model with another model when saving it

I have the following code. The product is like this: There's a book list. On each book item is a form. This form saves a post and makes it related to this particular book. When you click a book item, you see a list of posts, all related to this book item. So far the book list works fine, saving post data works fine, and when you click a list, it (the DetailView) shows the list of posts (instead of book description, which is usually how DetailView is used) fine. What's not working is saving the post to be related to the particular book on whom is the form that saves the post. More simply, when you save a post, the post should be related to the book that the form is located in.

I'd really appreciate your help. Thanks!

views.py:

class BookList(ListView):
model = Book
template_name='books/books.html'

    class PostForm(ModelForm):
        class Meta:
            model = Post
            # Previously I tried, unsuccessfully, this among others:
            # books = Book.objects.filter(book)
            # posts = Post.objects.filter(the_book=books)
            # model = posts
            fields = ['post']  
            widgets = {
            'post': forms.Textarea()
            }

    def get_context_data(self, **kwargs):
        context = super(BookList, self).get_context_data(**kwargs)
        context['form'] = BookList.PostForm
        return context

    def post(self, request, *args, **kwargs):
        form  = BookList.PostForm(request.POST)
        if form.is_valid():
            form.save()
        return render(request, self.template_name, {'form': form })

class Posts(DetailView):
    model = Book
    template_name='books/post_create.html'
    slug_field = 'id'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        book = self.object
        posts = Post.objects.filter(the_book=book)
        context['posts'] = posts
        return context

models.py:

class Book(models.Model):
    book = models.CharField(max_length=1000, blank=False, null=False, default="1")

    def __str__(self):
        return self.book

class Post(models.Model):
    post = models.CharField(max_length=1000, blank=False, null=False)
    the_book = models.ForeignKey('Book', on_delete=models.CASCADE, default="1")
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.post

books.html:

<ul>
{% for book in object_list %}
<div class='ui card'>
<a class="content" href='{% url 'books:posts' book.id %}'>
  <div class="header">{{ book }}</div>
</a>

<div class="ui bottom attached button">

   <form class='ui form' action='' method='post'> {% csrf_token %}
      {{ form.as_p }} 
      <div class='postbutton'>
      <input class='ui button' type="submit" value="Done" />
      </div>
  </form>

</div>

</div>
{% empty %}
<h5>You don't have any books!</h5>
{% endfor %}

post_create.html (the name will be changed later...):

<ul>
{% for post in posts %}
<div class='ui card'>
<a class="content">
  <div class="header">{{ post }}</div>
</a>
</div>
{% empty %}
<h5>You don't have any posts!</h5>
{% endfor %}

Upvotes: 0

Views: 60

Answers (1)

Greg
Greg

Reputation: 10352

Try this: add a book_id hidden input in your form:

<form class='ui form' action='' method='post'> {% csrf_token %}
  {{ form.as_p }} 
  <input type="hidden" name="book_id" value="{{ book.id }}">
  <div class='postbutton'>
  <input class='ui button' type="submit" value="Done" />
  </div>

and use it in your BookList view:

def post(self, request, *args, **kwargs):
    form  = BookList.PostForm(request.POST)
    if form.is_valid():
        post = form.save(commit=False)
        post.the_book_id = request.POST['book_id']
        post.save() 
    return render(request, self.template_name, {'form': form })

Upvotes: 1

Related Questions