0
votes

I'm trying to fetch subcategories from api, based on PAREND ID, using Vue and Django

So, I have 2 categories:

  • Phone Brands
  • Phone Models

Example:

Category: Sony, id:1 < Related subcategory: XZ3, XZ2, XZ...

Category: Samsung, id:2 < Related subcategory: S10, S9, S8...

So when the user click on 'Sony, id:1' category(router-link), I want all data based on that Category(parent)ID to be displayed on the screen(inside component). What is happening now, when I pass ID from parent to child component, response returns only 1 objects, that matches ID which I get from parent ID. Like, Sony(parent category) have ID:1, XZ3 (child category)have ID:1 too, so it show only matched ID inside component, nothing else


DJANGO

views.py:

from rest_framework import serializers
from . models import Specs, Models, Brands
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from . serializers import ModelsSerializer, SpecsSerializer, BrandsSerializer
# Create your views here.

@api_view(['GET'])
def BrandsView(request):
    brand = Brands.objects.all()
    serializer = BrandsSerializer(brand, many=True)
    return Response(serializer.data)

@api_view(['GET'])
def ModelsView(request, pk):
    model = Models.objects.get(pk=pk)
    serializer = ModelsSerializer(model, many=False)
    return Response(serializer.data)

@api_view(['GET'])
def SpecsView(request, pk):
    specs = Specs.objects.get(pk=pk)
    serializer = SpecsSerializer(specs, many=False)
    return Response(serializer.data)

urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.BrandsView),
    path('models/<pk>/', views.ModelsView),
    path('specs/<pk>/', views.SpecsView)
]

models.py

from django.db import models
from django.db.models.deletion import CASCADE
from django.urls import base, reverse
# from django_resized import ResizedImageField
from django.utils import timezone
# Create your models here.

class Brands(models.Model):
    brand = models.CharField(max_length=20)

    def __str__(self):
        return(f'{ self.brand }')

class Models(models.Model):
    brand = models.ForeignKey('Brands', on_delete=models.CASCADE, null=True)
    model = models.CharField(max_length=100)
    createdOn = models.DateField(default=timezone.now)
    warranty = models.BooleanField()
    damaged = models.BooleanField()
    repaired = models.BooleanField()
    firstOwner = models.BooleanField()
    price = models.IntegerField()

    def __str__(self):
        return(f'{ self.brand } - { self.model } / { self.price }e / Created: { self.createdOn }')

class Specs(models.Model):
    model = models.ForeignKey('Models', on_delete=models.CASCADE, null=True)
    dimensions = models.CharField(max_length=50)
    weight = models.CharField(max_length=10)
    screen = models.CharField(max_length=200)
    cpu = models.CharField(max_length=100)
    gpu = models.CharField(max_length=100)
    mainCam = models.CharField(max_length=50)
    selfieCam = models.CharField(max_length=50)
    video = models.CharField(max_length=100)
    battery = models.CharField(max_length=10)
    fastCharging = models.BooleanField()

    def __str__(self):
        return(f'{ self.model }')

serializers.py

from django.db import models
from django.db.models import fields
from . models import Specs, Models, Brands
from rest_framework import serializers


class BrandsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Brands
        fields = '__all__'
            
class ModelsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Models
        fields = '__all__'
    
class SpecsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Specs
        fields = '__all__'


VUE

index.js
import { createRouter, createWebHistory } from 'vue-router'
import About from '../views/About.vue'
import Models from '../views/Models.vue'
import Specs from '../views/Specs.vue'
import Brands from '../views/Brands.vue'

const routes = [
  {
    path: '/',
    name: 'Brands',
    component: Brands
  },
  {
    path: '/models/:id',
    name: 'Models',
    component: Models,
    props: true
  },
  {
    path: '/specs/:id',
    name: 'Specs',
    component: Specs,
    props: true
  },
  {
    path: '/about',
    name: 'About',
    component: About
  },
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

brands.vue

<template>
    <div>
        <h1> Brands </h1>
        <div v-for="brand in brands" v-bind:key="brand.brand">
            <router-link :to="{ name: 'Models', params: {id: brand.id} }"> 
                {{ brand }} 
            </router-link>
        </div>
    </div>
</template>
import axios from 'axios' export default { data(){ return { brands: [] } }, mounted(){ axios.get('http://localhost:8000/') .then(response => { this.brands = response.data }) }, }

Models.vue

<template>
    <div>
        <h1> Models </h1>
        <div v-if="models">
            <hr>
            <table>
                <tr>
                    <th> Model </th>
                    <th> Created </th>
                    <th> Warranty </th>
                    <th> Damaged </th>
                    <th> Repaired </th>
                    <th> First Owner </th>
                    <th> Price </th>
                    <!-- <th> More Specs </th> -->
                </tr>
                <tr>
                    <td> {{ models.model }} </td>
                    <td> {{ models.createdOn }} </td>
                    <td> {{ models.warranty }} </td>
                    <td> {{ models.damaged }} </td>
                    <td> {{ models.repaired }} </td>
                    <td> {{ models.firstOwner }} </td>
                    <td> {{ models.price }}e </td>
                    <th> 
<!--                         <router-link :to="{ name: 'Specs', params: {id: model.id} }"> 
                            HERE 
                        </router-link>  -->
                    </th>
                </tr>
            </table>
        </div>
    </div>
</template>

<script>
    import axios from 'axios'

    export default {
        props: ['id'],
        // template: ['id'],
        data(){
            return {
                models: []
            }
        },
        mounted(){
            axios.get('http://localhost:8000/models/' + this.id)
            .then(response => {
                this.models = response.data
            })
        }
    }
</script>

<style scoped>
    .models{
        background-color: lightcyan;
        border: 10px;
    }

</style>

Specs.vue

<template>
    <div v-if="specs" class="specs">
        <ul>
            <li> <b>Model:</b>          {{ specs.model }} </li> <br>
            <li> <b>Dimensions:</b>     {{ specs.dimensions }} </li> <br>
            <li> <b>Weight:</b>         {{ specs.weight }} </li> <br>
            <li> <b>Screen:</b>         {{ specs.screen }} </li> <br>
            <li> <b>Cpu:</b>            {{ specs.cpu }} </li> <br>
            <li> <b>Gpu:</b>            {{ specs.gpu }} </li> <br>
            <li> <b>Main Camera:</b>    {{ specs.mainCam }} </li> <br>
            <li> <b>Front Camera:</b>   {{ specs.selfieCam }} </li> <br>
            <li> <b>Video:</b>          {{ specs.video }} </li> <br>
            <li> <b>Battery:</b>        {{ specs.battery }} </li> <br>
            <li> <b>Fast Charging:</b>  {{ specs.fastCharging }} </li> <br>
        </ul>
        <hr>
        <router-link to="/"> Back to HOME </router-link>
    </div>
</template>

<script>
import axios from 'axios'

    export default {
        props: ['id'],
        data(){
            return {
                specs: [],
            }
        },
        mounted(){
            axios.get('http://localhost:8000/specs/' + this.id)
            .then(response => {
                this.specs = response.data
            })
        }
    }
</script>

<style scoped>
    .specs ul li {
        list-style-type: none;
        float: left;
    }
    /* .th {
        border: 1px solid;
        border-radius: 10px;
        padding: 20px;
        margin: 10% auto;
        box-shadow: 5px 5px 10px 5px ;
        background-color: aliceblue;
    } */
    .specs {
        background-color: lightcyan;
        border: 10px;
        padding: 10px;
    }

</style>
1
From your Brands serializer, you can show the nested Models information. Have a look here to get an idea on how to do itbdbd

1 Answers

0
votes

You need to create nested serializer between your Brands model and Models model. So you would add the following serializer class to your serializers.py, view to your views.py, and url path to your urls.py. Of course you can name the classes, functions, and url route whatever you'd like. Also, I would suggest you read up on the "nested serialization" chapter in the DRF docs.

// serializers.py
class Brands_ModelsSerializer(serializers.ModelSerializer):
    models = ModelsSerializer(source="models_set", many=True)
    class Meta:
        model = Brands
        fields = ['models']

// views.py
@api_view(['GET'])
def brand_with_models(request, pk):
    brand_models = Brands.objects.get(pk=pk)
    serializer = Brands_ModelsSerializer(brand_models)
    return Response(serializer.data)

// urls.py
path('brand_models/<pk>/', views.brand_with_models)