Django – Problem with Model Manager – Query

Question:

I’m still a beginner and I’m stuck in a challenging spot for me.
I can’t get data from a foreign key table to be inserted "correctly" into a column of a ListView.

I basically want to create a list view of a table (FeatureFilm). This also works. But in one column I get information from another table and here I get data, but not the one that belongs to the particular table row.

Here are my models. The table I want to show is "FeatureFilm" model. This model is inherited from my base Project class "ProjectBaseModel".
Then there is another table "CompanyInvolved Model". This is attached to the FeatureFilm table with a foreign key (feature_id).

So movies are stored (FeatureFilm) and different companies are involved in the creation process of the movies. (CompanyInvolved)

class ProjectBaseModel(models.Model):
    title = models.CharField("Titel", max_length=100, blank=False, unique=True)

    leading_postproduction_id = models.ForeignKey(
        Company,
        verbose_name="Federf├╝hrende Postproduktion",
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )
    phase = models.CharField(choices=post_phase, max_length=30, blank=True, null=True)
    former_title = models.CharField("Titel, ehemalig", max_length=100, blank=True)
    title_international = models.CharField(
        "Titel, international", max_length=100, blank=True, null=True, unique=True
    )

class FeatureFilm(ProjectBaseModel):
    class Meta:
        verbose_name = "Kinofilm"
        verbose_name_plural = "Kinofilme"
        ordering = ["title"]

class ProductionManager(models.Manager):
    def get_production(self):
        return (
            super()
            .get_queryset()
            .filter(company_role="Produktion", is_production_list=True)
            .values_list("company_involved__name")
        )


class CompanyInvolved(models.Model):
    feature_id = models.ForeignKey(
        FeatureFilm,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )
    tv_movie_id = models.ForeignKey(
        TvMovie, on_delete=models.CASCADE, null=True, blank=True
    )
    company_role = models.CharField(
        choices=company_role,
        max_length=15,
        blank=True,
        help_text="Produktion, Co-Produktion, Kinoverleiher, Sender, Weltvertrieb",
    )
    company_involved = models.ForeignKey(
        Company,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
    )


    is_production_list = models.BooleanField(
        default=False,
        verbose_name="Produktion in Liste",
    )
    productionmanager = ProductionManager()

    def __str__(self):
        return "#" + str(self.pk)

    class Meta:
        verbose_name = "Produktion, Co-Produktion, Verleih, Sender, Weltvertrieb"
        verbose_name_plural = "Produktion, Co-Produktion, Verleih, Sender, Weltvertrieb"
        ordering = ["pk"]

I basically wanted to generate the output now via the template. I can iterate the lines with the template for loop. But I also learned that more complex queries don’t work in the DjangoTemplate language, or simply don’t belong there.
I don’t need every row of data from the CompanyInvolved, but only the company_role = "Production" and is_production_list = True.
A combined "Where" clause in the template now nice, but doesn’t exist, so I built myself a MODEL MANAGER (ProductionManager) that does this filtering in the model.

here is the View:

class FeatureListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
    permission_required = "project.can_access_featurefilm_list"
    model = FeatureFilm
    template_name = "project/feature-list.html"

    def handle_no_permission(self):
        return redirect("access-denied")

ans here is the depending snippet in the template:

              <tbody>

                {% for project in object_list %}
                    <tr>

                        <td><a href="{% url 'feature-detail-date' project.pk %}">{{ project.title }}</a></td>

                        <td>{{ project.companyinvolved_set.get_production }}
                        <br>
                        </td>
                        <td>{% if project.program_length_planned %}
                                {{ project.program_length_planned }}
                            {% endif %}
                        </td>
                        <td>{{ project.global_shooting_resolution }}</td>
                        <td>{{ project.global_resolution_theatrical }}</td>
                        <td>{% if project.hdr == 1%}
                                ja
                            {% else %}
                                nein
                            {% endif %}

                        </td>
                        <td>{{ project.stafflist.postproduction_supervisor_id.username }}</td>
                        <td>{% if project.phase %}
                            {{ project.phase }}
                            {% endif %}

                        </td>


                    </tr>

                  {% endfor %}
              </tbody>

so I iterate over each movie project with {% for project in object_list %} and then I want to show in my "problem" column the company that has the role production and since there can be more than one, the one that was previously marked by the user for the lists view – > is_production_list = TRue and then the output should come: {{ project.companyinvolved_set.get_production }}.

The result is going in the right direction, but it is still not finally correct. I get the CompanyINvolved data and these are also filtered by company_role = "Production" and is_production_list = True , but these values are now displayed to me each time in each individual Row the same, I get so not per ROW the associated productions but simply each time ALL. I’m missing the reference to the FeatureFilm object, but I don’t know how to get this now, or where to put this reference now?

changed my template:

 <tbody>

                {% for project in object_list %}
                    <tr>

                        <td><a href="{% url 'feature-detail-date' project.pk %}">{{ project.title }}</a></td>

                        <td>
                          !! {{ project.production_companies.company_involved.name}}!!
                            <br>
                        </td>
                        <td>{% if project.program_length_planned %}
                                {{ project.program_length_planned }}
                            {% endif %}
                        </td>
                        <td>{{ project.global_shooting_resolution }}</td>
                        <td>{{ project.global_resolution_theatrical }}</td>
                        <td>{% if project.hdr == 1%}
                                ja
                            {% else %}
                                nein
                            {% endif %}

                        </td>
                        <td>{{ project.stafflist.postproduction_supervisor_id.username }}</td>
                        <td>{% if project.phase %}
                            {{ project.phase }}
                            {% endif %}

                        </td>


                    </tr>

                  {% endfor %}
          </tbody>
Asked By: gomez_

||

Answers:

I think your code is not working because get_production calls super().get_queryset(), which returns a new QuerySet, without any filters applied, not based on the Queryset in the reverse look up in companyinvolved_set

Your best bet is to add a @property annotation to access the filtered list through your FeatureFilm model

@property
def production_companies(self):
        return [company for company in self.companyinvolved_set.all() if company.company_role == 'Produktion' and company.is_production_list]

Then add this to your template:

<td>{% for production in project.production_companies %}{{production.company_involved.name}}{% endfor %}</td>

And to prevent a lot of queries, change the get_queryset method in your view to this:

def get_queryset(self):
    queryset = FeatureFilm.objects.prefetch_related('companyinvolved_set').all()
    return queryset
Answered By: Nico Griffioen