Django e-commerce part27 Related Products
Related Productsの表示
models.py のproductmanagerに、get_relatedのfuncを追記する。
class ProductManager(models.Manager): ... def get_related(self, instance): return self.get_queryset()
views.py のProductdetailVIewのcontextを更新
related productsは、detailviewに表示するので、detailviewに追記する。 get_context_dataを上書きする。
class ProductDetailView(DetailView): model = Product def get_context_data(self, *args, **kwargs): context = super(ProductDetailView, self).get_context_data(*args, **kwargs) context["related"] = Product.objects.get_related() return context
views.py のtype errorを解消する
このままrunserverを実行すると、get_related() missing 1 required positional argument: 'instance' errorが表示されてしまう。この原因は、 def get_related(self, instance): self以外にあと1つinstanceの引数をとるため。そのため、instanceの引数をviews.pyで追記する。現時点では、get_relatedに、instanceを設定してないので、結果に影響はない。
class ProductDetailView(DetailView): model = Product def get_context_data(self, *args, **kwargs): context = super(ProductDetailView, self).get_context_data(*args, **kwargs) instance = self.get_object() print (instance) context["related"] = Product.objects.get_related(instance) return context
- instance = self.get_object() に関しては、ProductDetailView().get_object() で、titleを返すようになっている。
ProductManagerとProductの関係について
- Productで、
objects = ProductManager()
と挿入することによって、本来modelsに備わっている、Product.objects というメソッド?プロパティ?が上書きされる。そのため、ProductManagerに、get_relatedを定義しておくと、Product.objects.get_related()というメソッドをProductDetailViewで、利用することが可能。
models.py にget_relatedを追記していく
class ProductManager(models.Manager): ... def get_related(self, instance): products_one = self.get_queryset().filter(categories__in=instance.categories.all()) products_two = self.get_queryset().filter(default=instance.default) qs = (products_one | products_two ).exclude(id=instance.id).distinct() return qs ...
products_one: instance.categories.all()は、ProductDetailView.get_objcet().categories.all()を想定している?結果的には、instanceに登録されているcategoriesが、含まれているかどうかで、filterをかけて、querysetをゲットしている。
products_twoは、defaultで、filterをかけている。
qs は、products_one + products_two - 自分 - 重複分を差し引いてリスト化
exclude(id=instance.id)
で、selfがrelatedに含まれないようにしている。
product_detail.html を編集
product_list.htmlからコードをコピペして変数の箇所は修正しておく。
{% for product in related %} <tr> <td><a href='{{ product.get_absolute_url }}'>{{ product.title }}</td> </tr> </br> {% endfor %
views.py のProductDetailViewに追記
- orderの順番がランダムになる? order_by("?")を追記
context["related"] = Product.objects.get_related(instance).order_by("?")
- 表示する件数を制限する。
context["related"] = Product.objects.get_related(instance).order_by("?")[:6]
上記の追記は、modelに追記でも可。ただ、表示に関することなので、viewに書いておいた方が無難かも。
models.py のProductにclass Metaを記載してみる。
class Product(models.Model): ... class Meta: ordering = ["-title"]
これで、基本的には、-titleで表示されるが、viewで、表示順を指定しておけば、modelの設定に関係なく表示を設定できる。