LoginSignup
Reiku
@Reiku (Rei k)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Djangoのモデルをテンプレートに表示できない

解決したいこと

Djangoのテンプレートにモデルを表示させたいです。

{% for product in products %}
{{ product.name }}
{% endfor %}
だと表示されるのですが、tagsに変更すると
shop.PostTag.None と表示されてしまうので
解決方法教えていただきたいです。

発生している問題・エラー

shop.PostTag.None

テンプレートの記述スクリーンショット 0004-06-21 17.30.38.png

エラー1スクリーンショット 0004-06-21 17.20.56.png

views.py の記述スクリーンショット 0004-06-21 17.30.57.png

エラー2スクリーンショット 0004-06-21 17.30.17.png

model.py

from django.db import models
from django.urls import reverse
from django.shortcuts import render


class PostTag(models.Model):
    name = models.CharField(max_length=200)
    
    def __str__(self):
        return self.name

def image_path(instance, filename):
    ext = filename.split('.')[-1]
    new_name = instance.name
    return f'producthover/{new_name}.{ext}'

class Product(models.Model):
    name = models.CharField(verbose_name='商品名', max_length=250, unique=True)
    slug = models.SlugField(verbose_name='URLに表示される名前', max_length=250, unique=True)
    description = models.TextField(verbose_name='説明', blank=True)
    price = models.IntegerField()
    image = models.ImageField(upload_to='product', blank=True)
    hover_image = models.ImageField(verbose_name='ポップアップの画像', upload_to=image_path, blank=True, )
    stock = models.IntegerField()
    available = models.BooleanField(default=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    tags = models.ManyToManyField(PostTag)

    objects = models.Manager()

    valid_objects = ValidManager()

    class Meta:
        ordering = ('name',)
        verbose_name = 'product'
        verbose_name_plural = 'products'
    def __str__(self):
        return '{}'.format(self.name)

    def get_url(self):
        return reverse('shop:product_detail', args=[self.slug])

    def index(request):
        image_request = request.user.set_image_path
        return render(request, 'shop/base.html', {'image_request': image_request}) 

views.py

from django.shortcuts import render

from shop.models import Product

from django.core.paginator import Paginator, EmptyPage, InvalidPage


def all_products(request):
    products_list = Product.valid_objects.all()

    paginator = Paginator(products_list, per_page=16)
    try:
        page = int(request.GET.get('page', '1'))
    except:
        page = 1

    try:
        products = paginator.page(page)
    except (EmptyPage, InvalidPage):
        products = paginator.page(paginator.num_pages)
        
    return render(request, 'shop/product_list.html', {'products': products})
0

3Answer

解決いたしました。
私の解決方法としましては、行動できなくなったのでgitで前のバージョンに戻したら解決いたしました。
参考にならず申し訳ございません。

基本的には、下記の記述を加えると解決できると思います。

"HTML"

{% for product in products %}
{% for tag in product.tags.all %}
{{ tag.name }}
{% endfor %}
{% endfor %}
1

views.pyでは、今のままでも動くと思います

強いていうなら、prefetch_relatedを実行しておいた方がよいです。
今のままでだと、テンプレートのforループで、product.tags.allを呼び出す度にsqlが実行されます。
結果、productの数だけ、sqlが実行されてしまい、sqlサーバに負荷がかかってしまいます。

prefetch_relatedを使うと、事前に各productのtagsをキャッシュすることで、sqlの実行回数を減らせます。

views.py
def all_products(request):
    products_list = Product.valid_objects.all().prefetch_related('tags')
     # あとは、同じで大丈夫です。
0

Comments

  1. @Reiku

    Questioner
    ご丁寧にありがとうございます。困っていましたので非常に助かります。
    Mt_Snow様が最初に答えてくださった。2つ目のテンプレートのコードを記述しても表示されませんでした。(エラー1)
    1つ目の 「tag_list = product.tags.all()」 このコードはどこに記述すればよろしいでしょうか。
    こちらのコード 「prefetch_related('tags')」 を追加するとエラーが発生しました。(エラー2)
    エラーの画像は本質問に追加しておきました。
    質問ばかりになってしまい本当に申し訳ございません。詰まってしまっていて困っているのでお答えいただき非常に感謝しております。
  2. まず、prefetch_related('tags')はなくても動くはずなので、一旦無視して、1つ目のテンプレートの追記のみの場合にフォーカスして考えます。

    実行例が空白になってますが、DBに設定済みのproductにはtagsに値がちゃんと入っていますか?
    また、設定されているtagのnameも値が入っていますか?
  3. @Reiku

    Questioner
    解決いたしました。本当にありがとうございます。
  4. お力になれたかはわかりませんが、解決できたようでよかったです。
    後で、同じような問題に行き詰った別の方がこの質問をご覧になることもありますので、
    もしお手間じゃなければ、どのように解決したか、簡単でもいいので、コメントとして残していただけますでしょうか?
  5. @Reiku

    Questioner
    失礼いたしました。わざわざありがとうございます。

ManyToManyFieldは直接表示できません。
ManyToManyFieldは下記のように一覧を取得する必要があります。

# Productのtag一覧を取得
tag_list = product.tags.all()

テンプレで表示するするなら以下の様な形になります

{% for product in products %}
{% for tag in product.tags.all %}
{{ tag.name }}
{% endfor %}
{% endfor %}

0

Comments

  1. @Reiku

    Questioner
    ご返信ありがとうございます。
    もしよろしければ、views.py にどのように記述すればよいか教えていただいてもよろしいでしょうか。

Your answer might help someone💌