В Django я пытаюсь вывести список объектов из разных моделей в детальном представлении, основанном на классах.

У меня есть две модели Vendors и Products. У Products есть внешний ключ vendors. Я пытаюсь сделать так: когда вы переходите к детальному представлению поставщика, он показывает информацию о модели поставщика, а затем список товаров этого поставщика.

В настоящее время я только тестирую поток и знакомлюсь с django, поэтому многое в этом коде очень общее, и я знаю, что мне нужно его очистить.

Вот мои модели

class Vendor(models.Model):
    name = models.CharField(max_length=126, unique=True, blank=True, null=True)
    contact_number = models.CharField(max_length=126, blank=True, null=True)
    address = models.CharField(max_length=126, blank=True, null=True)
    email = models.EmailField(max_length=126, blank=True, null=True)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.name

def productFilepath(instance, filename):
    year = datetime.now().strftime("%Y/")
    return os.path.join(instance.vendors.name, year, filename)

class Product(models.Model):
    vendors = models.ForeignKey(Vendor, on_delete=models.CASCADE)
    collection = models.CharField(max_length=126, unique=True, blank=True, null=True)
    product = models.CharField(max_length=126, blank=True, null=True)
    size = models.CharField(max_length=126, blank=True, null=True)
    vendor_price = models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True)
    retail_price = models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True)
    sku = models.CharField(max_length=126, unique=True, blank=True, null=True)
    year = models.PositiveSmallIntegerField(blank=True, null=True)
    quarters_in_year = {
        'q1': 'Q1',
        'q2': 'Q2',
        'q3': 'Q3',
        'q4': 'Q4',
    }
    quarter = models.CharField(max_length=2, choices=quarters_in_year.items(), blank=True, null=True)
    image = models.FileField(upload_to=productFilepath, blank=True, null=True)

вот мои взгляды

class VendorDetailView(DetailView):
    model = Vendor
    template_name = 'deliveries/vendor_detail.html'


class Productlist(ListView):
    model = Product
    template_name = 'deliveries/vendor_detail.html'
    def get(self, request, *args, **kwargs):
        return super().get(request, *args, **kwargs)

URL

path('vendordetail/<int:pk>/', views.VendorDetailView.as_view(), name='vendordetail'),

HTML

{% extends "base.html" %}
{% block style_block %}
    <style>
    #title {
       padding: 20px;
    }
    
    .add-button {
        background-color: #04AA6D;
        border: none;
        color: white;
        padding: 15px 32px;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 16px;
        margin: 4px 2px;
        cursor: pointer;
        float: right;
    }
    </style>
{% endblock %}
    {% block body_block %}   
        
        <h1 id="title">{{  vendor.name }}</h1>
        
        <a href="{% url "deliveries:addproduct" %}"><button class="button add-button" type="button">Add Product</button></a> 
    <ul>
        <li>{{ vendor.name }}</li>
        <li>{{ vendor.contact_number }}</li>
        <li>{{ vendor.email }}</li>
        <li>{{ vendor.address }}</li>
    </ul>
        
        <a href="{% url "deliveries:uploadproduct" %}"><button class="button add-button" type="button">Upload</button></a> 
        
        <div>
            <h1>Products</h1>
    
{#    <form  >#}
{#    {% csrf_token %}#}
{#    {{ form.as_p }}#}
{#    <input type="submit" value="submit">#}
{#</form>#}
    
    
        <table style="width:100%">
  <tr>
      <th>SKU</th>
      <th>Collection</th> 
      <th>Product Name</th> 
      <th>Size</th>
      <th>Vendor Price</th>
      <th>Retail Price</th>
  </tr>
        {% for product in products %}
  <tr>
    <td>{{ product.sku }}</td>
    <td>{{ product.collection }}</td>
    <td>{{ product.product }}</td>
    <td>{{ product.size }}</td>
    <td>${{ product.retail_price }}</td>
    <td>${{ product.vendor_price }}</td>
  </tr>
        {% empty %}
    <li>No articles yet.</li>
{% endfor %}
</table>
        </div>
        
        
     {% endblock %}


Итак, я решил создать представление списка, которое указывает на шаблон детального представления. Я попробовал это и думаю, что не работает то, что мне нужно передать PK от продавца, чтобы получить только товары от этого продавца. PK уже находится в URL из детального представления.

Я думал, что это поможет получить PK, но не получилось.

    def get(self, request, *args, **kwargs):
        return super().get(request, *args, **kwargs)

Я также попробовал сделать что-то подобное. Это было то, что я тестировал для фильтрованного поиска и подумал, что это может сработать.

class ProductList(ListView):
    model = Product
    template_name = 'deliveries/vendor_detail.html'
    context_object_name = 'products'

    def get_queryset(self):
        pk = self.kwargs['pk']
        queryset = super().get_queryset()
        self.filterset = ProductFilter(self.request.GET, queryset=queryset)
        return self.filterset.qs

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.filterset.form
        return context

Я не уверен, что лучший способ сделать это. Если создание двух представлений, указывающих на один шаблон и пытающихся передать PK из url, является правильным способом.

Чтобы получить все продукты от поставщика, необходимо добавить "related_name" в модель продукта

class Product(models.Model):
    vendors = models.ForeignKey(
        Vendor, 
        on_delete=models.CASCADE, 
        related_name="products",
    )
    ...

А в html просто добавьте vendor.products.all

 <h4>Products:</h4>
 <ul>
     {% for product in vendor.products.all %}
         <li>{{product.name}}</li>
     {% endfor %}
 </ul>
Вернуться на верх