Problem z pętlą w Django views.py

0

Cześć,

Potrzebuję zrobić pętle dla:

def home(request):
    context = {
        'highlights0':
            {Movie.objects.all()[0]: Movie.objects.all()[0].cinemas_that_play_it()},
        'highlights1':
            {Movie.objects.all()[1]: Movie.objects.all()[1].cinemas_that_play_it()},
        'highlights2':
            {Movie.objects.all()[2]: Movie.objects.all()[2].cinemas_that_play_it()},
    }

W Django SHELL

>>> print(context)
{'highlights0': {<Movie: Film 1>: <QuerySet [<Projection: Film 1 at Helios on 17.04.2022 20:10:13>]>}, 'highlights1': {<Movie: Film 2>: <QuerySet [<Projection: Film 2 at Cienma on 17.04.2022 20:10:27>]>}, 'highlights2': {<Movie: Film 3>: <QuerySet [<Projection: Film 3 at Mini kino on 17.04.2022 20:22:09>]>}}

Już mnie to przerosło. Ma ktoś pomysł jak to zrobić prawidłowo?
Dopiero uczę się Django.

3
context = {f"highlights{i}":{Movie.objects.all()[i]:Movie.objects.all()[i].cinemas_that_play_it()} for i in range(Movie.objects.count()}

Ogólnie to wołanie (tak jak chcesz) tego objects.all() w każdej iteracji mocno Ci zwolni apkę. Wsadź jeden taki call w zmienna i potem sobie z niej wyciągaj pojedyncze obiekty.

0

@ledi12: Dzięki działa.
Czy sugerujesz, żeby nie robić tak?

def home(request):
    context = {f"highlights{i}":{Movie.objects.all()[i]:Movie.objects.all()[i].cinemas_that_play_it()} for i in range(Movie.objects.count())}
    return render(request, "cinemas/index.html", context)

Żeby zmienną context robić poza funkcją?

A czy wywołanie w templates, żeby wyświetlić powinno iść w tym kierunku? Na razie jeszcze nie działa. Szukam rozwiązania.

{% for i in '0123456789'|make_list %}
    {% if highlights{{ forloop.counter }} %}
        {% for name, details in highlights{{ forloop.counter }}.items %}
        {%for detail in details%}{{detail}} {%endfor%}
        {% endfor %}
{% endfor %}
0

Wygląda to wszystko bardzo dziwnie. Co chcesz osiągnać co to ma pokazywać pobierać?

0

@Rado: W pliku views.html staram się pobrać wszystkie returny z moich obiektów. Mam ich trzy a może będzie cztery.

def home(request):
    context = {
        'highlights0':
            {Movie.objects.all()[0]: Movie.objects.all()[0].cinemas_that_play_it()},
        'highlights1':
            {Movie.objects.all()[1]: Movie.objects.all()[1].cinemas_that_play_it()},
        'highlights2':
            {Movie.objects.all()[2]: Movie.objects.all()[2].cinemas_that_play_it()},
    }

I wyświetlić w HTML

{% extends "cinemas/base.html" %}

{% block title %}Sieć kin Cinemas{% endblock %}

{% block content %}
<h1>Sieć kin Cinemas:</h1>
{% for x in highlights0.items %}
{% for name, details in highlights0.items %}
{%for detail in details%}{{detail}} {%endfor%}
{% endfor %}

</p>
{% for name, details in highlights1.items %}
{%for detail in details%}{{detail}} {%endfor%}
{% endfor %}
</p>
{% for name, details in highlights2.items %}
{%for detail in details%}{{detail}} {%endfor%}
{% endfor %}

{% endblock %}

Z tym, że tutaj na sztywno zakładam, że będę trzy rzeczy do wyświetlenia a myślę o pętli, która sama to wykryje i zrobić output odpowieniej ilości elementów.

Tak wygląda models.py

from django.db import models
from django.core.validators import MaxValueValidator, MinValueValidator

class Cinema(models.Model):
    name = models.CharField(max_length=100)
    seats = models.PositiveSmallIntegerField(validators=[MinValueValidator(10)])

    def __str__(self):
        return self.name

class Movie(models.Model):
    title = models.CharField(max_length=100)
    minimum_age = models.PositiveSmallIntegerField(validators=[MaxValueValidator(21)])

    def __str__(self):
        return self.title

    def cinemas_that_play_it(self):
        return self.projection_set.all()

class Projection(models.Model):
    cinema = models.ForeignKey(Cinema, on_delete=models.CASCADE)
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
    date = models.DateTimeField()
    published = models.BooleanField()
    tickets_available = models.PositiveSmallIntegerField()

    def __str__(self):
        return f"{self.movie.title} at {self.cinema.name} on {self.date.strftime('%d.%m.%Y %H:%M:%S')}"

1
highlights = Movie.objects.prefetch_related('projection_set').all()[:3] -> tylko 3 obiekty

context = {
  'highlights': highlights

}

Template

{% for movie in highlights %}
  {%for projecton in movie.projection_set.all %}
      {{projecton}}
  {%endfor%}
{% endfor %}
debek napisał(a):

@Rado: W pliku views.html staram się pobrać wszystkie returny z moich obiektów. Mam ich trzy a może będzie cztery.

Co to znaczy? Dlaczego tylko 3? Nie mogą w jednej zmiennej być te trzy i normalne iterowanie tylko jakoś takie dziwne rzeczy?

def cinemas_that_play_it(self):
    return self.projection_set.all()

Chyba do wywalenia? Na takie rzeczy jak tu będzie filter w przyszłości to raczej się robi Manager https://docs.djangoproject.com/en/4.0/topics/db/managers/

Jak chcesz tylko do 3 żeby jedno w templatce pokazywalo a drugie to może coś w ten deśen.

{% if {{ forloop.counter }} < 3 %}

Może jest za wcześnie i nie czaje czemu tak po rusku to dzielisz.

0

Mój poziom jeszcze jest ruski ;)
Nie dziele. To był przykład bo dodałem trzy obiekty Projection w admin :P Chodziło mi o normalne iterowanie.
Zaraz potestuję i poprawię kod :)

0

Zastanawiam się jaka jest różnica pomiędzy?:

  1. >>> Movie.objects.all()
    <QuerySet [<Movie: Film 1>, <Movie: Film 2>, <Movie: Film 3>]>
    
  2. >>> Movie.objects.prefetch_related('projection_set').all()
    <QuerySet [<Movie: Film 1>, <Movie: Film 2>, <Movie: Film 3>]>
    
  3. >>> Movie.objects.prefetch_related('projection_set')
    <QuerySet [<Movie: Film 1>, <Movie: Film 2>, <Movie: Film 3>]>
    
2

Do poczytania django N+1

1 użytkowników online, w tym zalogowanych: 0, gości: 1