Home > database >  Django model with multiple foreign keys
Django model with multiple foreign keys

Time:05-27

I want to create a list of products that are categorized by area, need, and product category. I created 3 separate models that reply on each other so users will easily add categories and select from the dropdown list area and need.

For now, I have 3 areas and under each area I have needs. What I want is to render a list of items from Area model, under each item from Area model all items from Need model and under each item from Need model all items from Product model (only titles).

ProductCategory model is not used here but I need it somewhere else and it is a connector between products and areas/needs. It is much easier to define categories and just select them from the dropdown list when adding a new product.

I need to create a loop that will show me something like above. I know it will not work but I wanted to show the logic.

My question is what is the best approach to render something like this?

How can I get category_area and category_need in my class and in my html?

models.py

class Area(models.Model):
    title = models.CharField(max_length=75, blank=False)
    body = models.CharField(max_length=150, default='-', blank=False)
    publish = models.DateTimeField('publish', default=timezone.now)   

class Need(models.Model):
    title = models.CharField(max_length=75, blank=False, null=False, help_text='max 75 characters')
    body = models.CharField(max_length=150, default='-', blank=False)
    publish = models.DateTimeField(default=timezone.now)
    need_area = models.ForeignKey(Area, on_delete=models.CASCADE, related_name='need_area')

class ProductCategory(models.Model):
    title = models.CharField(max_length=400, blank=False, null=False, help_text='max 400 characters')
    body = models.TextField(default='-')
    publish = models.DateTimeField('publish', default=timezone.now)
    category_area = models.ForeignKey(Area, on_delete=models.CASCADE, related_name='category_area', null=True)
    category_need = models.ForeignKey(Need, on_delete=models.CASCADE, related_name='category_need', null=True)

class Product(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=400, blank=False)
    category = models.ForeignKey(ProductCategory, on_delete = models.CASCADE, blank=True, related_name='products')

    def get_absolute_url(self):
        return reverse("product", kwargs={'slug': self.slug})

views.py

class SearchProducts(LoginRequiredMixin, ListView):
    login_url = 'login'
    redirect_field_name = 'login'
    template_name = 'hubble/search/manual_search.html'
    model = Product
    queryset = Product.objects.all()
    
    def get_context_data(self, **kwargs):
            context = super(SearchProducts, self).get_context_data(**kwargs)
            product_results = ProductCategory.objects.prefetch_related("products").all()
            context['product_results'] = product_results
            return context

product_search.html

    <div>
    {% for area in product_results %}
        <h6>{{area.title}}</h6>
    {% endfor %}
    </div>

CodePudding user response:

You can prefetch_related all backwards relationship and make an iteration similar to this:

areas = Area.objects.prefetch_related('need_area__category_need__products')

for area in areas:
    # iterate through each instance of Area
    for need in area.need_area.all():
        # iterate through  each instance of Need for the given area
        for product_category in need.category_need.all():
            # iterate through each instance of ProductCategory for the given need
            for product in product_category.products.all():
                # iterate through each instance of product for the given product category
  • Related