简体   繁体   中英

Django: How to Join One-to-many relationship? / Show joined query in template

I am new in Django. I am trying to make a clone of craiglist. Currently I have to models: Posts and Media (images). One post can have many Media. I want to show first image that was posted by user when they create a post as well as info about post on the index page. Unfortunately I can't properly join Media when I refer to Posts and vice versa. How to properly show post and media instances in index template?

Models:

class Post(models.Model):
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=1500)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
    subcategory = models.ForeignKey(Subcategory, on_delete=models.SET_NULL, null=True)
    price = models.DecimalField(max_digits=12, decimal_places=2)
    city = models.CharField(max_length=200)
class Media(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    name = models.CharField(max_length=500, null=True, blank=True)
    photo = models.ImageField(upload_to='photo/%Y/%m/%d/', null=True, blank=True)

Views:

def index(request):
    posts = models.Media.objects.all()
    paginator = Paginator(posts, 2)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    return render(request, 'aggregator/index.html', {'page': page_obj})

index.html template:

{% for media in page %}
            <div class="col">
                <div>
                    <p>Picture</p>
                </div>
                <div>
                    <h4><a href="{% url 'show_post' post_id=media.post.id %}">{{ media.post.title|upper }}</a></h4>
                </div>
                <div>
                    <h5>{{media.post.price}}$</h5>
                </div>
                <div>
                    <h6>{{media.post.city}}</h6>
                </div>
            </div>    
        {% endfor %}

So again. How to normally join first media related to the posts? Like in the attached screenshot. 在此处输入图像描述

I found a solution to get posts from Media:

posts = models.Media.objects.all()

instead of getting posts themselves (i know this is horribly wrong) because I do not understand how to join Media: select_related and prefetch_related don't work - there is an error like this:

posts = models.Post.objects.select_related('Media').all()

Invalid field name(s) given in select_related: 'Media'. Choices are: user, category, subcategory

To display the results of a joined query in a Django template, you will need to pass the queryset to the template context and then use a for loop to iterate over the objects in the queryset.

Here's an example of how you can do it in your view function:

 from django.shortcuts import render from.models import Model1, Model2 def view_function(request): queryset = Model1.objects.select_related('model2').all() return render(request, 'template.html', {'objects': queryset})

In your template, you can then use a for loop to iterate over the objects in the queryset and access the fields of each object using dot notation.

For example:

 {% for obj in objects %} {{ obj.field1 }} - {{ obj.model2.field2 }} {% endfor %}

You can prefetch with:

def index(request):
    posts = models.Post.objects
    paginator = Paginator(posts, 2)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    return render(request, 'aggregator/index.html', {'page': page_obj})

Then in the template render with:

{% for post in page %}
<div class="col">
  <div>
    {% if post.media_set.all.0.photo %}
      <img src="{{ post.media_set.all.0.photo.url }}">
    {% endif %}
  </div>
  <div>
    <h4><a href="{% url 'show_post' post_id=post.pk %}">{{ post.title|upper }}</a></h4>
  </div>
  <div>
    <h5>{{ post.price }}$</h5>
  </div>
  <div>
    <h6>{{ post.city }}</h6>
  </div>
</div>    
{% endfor %}

The .prefetch_related is not even necessary, but it will slow the view down, because then it will make a query per Post , not one extra query to fetch all Media objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM