製品名をフィルタリングしてデータベースに1回だけアクセスすることにより、2つのDjangoモデルから製品と画像を取得します

Nov 29 2020

eコマースWebサイト用に2つのDjangoモデルがあります。

class Product(models.Model):
    name=models.CharField(max_length=300)
    description=models.CharField(max_length=10000)

class Thumnbnail(models.Model):
    thumnbnail=models.ImageField(null=True)
    product=models.ForeignKey(Product, related_name='related_product', on_delete=models.CASCADE)

ユーザーがいくつかのキーワードを入力すると、そのキーワードで製品名をフィルタリングし、それらの製品のみを表示します。すべての商品について、結果ページで、すべての商品のサムネイルもすぐに読み込んで表示したいと思います。

同じビューセットと同じクエリセットで両方のモデルを効率的な方法で取得するにはどうすればよいですか?

私はこれを2つの別々のクエリセットで達成できることを知っています。

queryset = Product.objects.filter(name__contains="Fanta").all()
return queryset

およびサムネイルの他のビューセット

queryset = Product.objects.select_related('thumbnail').filter(name__contains="Fanta").all()
return queryset
# I will create another serializer to only show the thumbnails, for this specific queryset

私は最後のものを最も正しく書いていなかったかもしれません、私はただ疑似コードを書いています、しかし私はそれをする方法を知っています。

私のポイントは、inputキーワードを使用してproduct_namesの同じフィルタリングを2回実行する必要があるということです。1回目はProductViewsetで製品名と説明を取得し、もう1回は同じフィルタリングを実行してThumbnailViewsetからサムネイルを取得します。

これを回避し、フィルタリングを1回だけ行うにはどうすればよいですか?

.select_related()がどのように機能するかを知っています。単一のデータベースヒットで、両方のモデル製品の両方のテーブルとサムネイルを取得できます。しかし、それらを一緒に表示し、単一のクエリセットで返すにはどうすればよいですか?その後、単一のシリアライザーに戻ると、Productのフィールド名と説明が次のように繰り返されます。

fields= [ product_id, product_name, product_description, thumbnail_id, thumbnail_filepath]

したがって、すべてのサムネイルについて、product_description全体が何度も繰り返され、10.000文字になる可能性があるため、ページに多数の製品が表示されると、サーバーからクライアントへのデータの転送に時間がかかります。また、サムネイルごとに説明を繰り返す必要はありません。しかし、最も効率的な方法で、すべての製品サムネイルを含む製品説明を1回だけ取得するにはどうすればよいですか?

回答

1 AlexElizard Nov 30 2020 at 14:15

Еслияправильнопонялвопрос、попробуйтеэто

# serializers.py
from rest_framework import serializers
from .models import Product


class ProductSerializer(serializers.ModelSerializer):
     thumnbnails = serializers.PrimaryKeyRelatedField(many=True, read_only=True,sourse='related_product')

     class Meta:
        model = Product
        fields = ['name', 'description', 'thumnbnails']


# views.py
...
from .serializers import ProductSerializer

....

queryset = Product.objects.filter(name__contains="Fanta").prefetch_related('related_product')
serializer = ProductSerializer(queryset, many=True)
return serializer.data

....