CreateView that can return other Model data

Hi
I have this view, which is working fine but I want to display info from another Model (Books) on the top of the form in the same template.
What is the best way of doing it?

    model = Posts
    fields = ['title', 'content']

    def form_valid(self, form):
        form.instance.posted_by = self.request.user
        form.instance.bookid_id = self.kwargs['pk']
        form.save()
        return super().form_valid(form)```

```class Books(models.Model):
    sessaoid = models.ForeignKey(Sessoes, on_delete=models.CASCADE)
    book_name = models.CharField(max_length=100)
    author = models.CharField(max_length=50, default='Autor')
    description = models.CharField(max_length=250)
    sinopse = models.TextField()
    image = models.ImageField(upload_to='books/')
    presented_by = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.book_name

    def get_absolute_url(self):
        return reverse('book:detalhe_livro', kwargs={'pk': self.pk})

class Posts(models.Model):
    bookid = models.ForeignKey(Books, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content =models.TextField()
    date_posted = models.DateTimeField(default=timezone.now)
    posted_by = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('book:index')````

Thanks in advance

I’m guessing you’re using a CBV given you’re showing a form_valid method. If so, what you’re looking for is the get_context_data method to add additional data to the context to be rendered.

Hi Ken
Yes I am, the first line for some reason didn’t show up, here it is:

class PostsCreateView(CreateView):

I’ve tried that but I’m not getting any data or errors. I’m using a different Model on the get_context_data, could that be the reason?

Nope, absolutely not. You would use get_context_data to add any data to the context to be rendered.

Please show the complete view. We’re probably also going to need to see the template as well.

Side note: The three backticks (```) used to markup your code must be lines by themselves. They must not be the beginning or end of any of the code being fenced.

Ok, here is the view and the template

class PostsCreateView(CreateView):
    model = Posts
    fields = ['title', 'content']
    context_object_name = 'thebook'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context ['book'] = Books.objects.get(pk=self.kwargs['pk'])
        return context

    def form_valid(self, form):
        form.instance.posted_by = self.request.user
        form.instance.bookid_id = self.kwargs['pk']
        form.save()
        return super().form_valid(form)

and the template

{% extends "books/base.html" %}
{% load crispy_forms_tags %}

{% block content %}
    {% for b in thebookk %}
        <div>
            <h2>Este é o livro que está a comentar: {{ b.book_name }}</h2>
        </div>
    {% endfor %}

    <div class="content-section">
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Criar Post</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Criar</button>
            </div>
        </form>
    </div>
{% endblock content%}

Two things.

  • The name of the object in the context is book, not thebookk.

  • You’re using the get method, which returns a single item, not an iterable. You can reference the fields directly from book.

Side note: CreateView is designed to render a blank form. There’s no value in defining context_object_name in this class - it’s never going to be used.

1 Like

You are, as always, absolutely right. I’ve made the changes and it’s working. Here they are.
Thank you very much Ken!

class PostsCreateView(CreateView):
    model = Posts
    fields = ['title', 'content']

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context ['book'] = Books.objects.get(pk=self.kwargs['pk'])
        return context

    def form_valid(self, form):
        form.instance.posted_by = self.request.user
        form.instance.bookid_id = self.kwargs['pk']
        form.save()
        return super().form_valid(form)
```

```
{% block content %}
        <div>
            <h2>Este é o livro que está a comentar: {{ book.book_name }}</h2>
        </div>

    <div class="content-section">
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Criar Post</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Criar</button>
            </div>
        </form>
    </div>
{% endblock content%}
```