5

I am trying to search for all serial numbers with a specific sales_order(foreign key) field by providing the sales order as a url parameter to its viewset. I'm not sure why my queryset isn't being displayed by a GET request

This is a new system I am developing, and as a django newbie I am having some trouble getting everything working the way I'd like it too. Currently, I have configured my routes so that 127.0.0.1:8000/api/serialWSales/ just displays all serial numbers, and I want to have 127.0.0.1:8000/api/serialWSales/(<sales_order>)/ to display only the serial numbers with the sales order number given. I was able to get and print the desired queryset based on the sales_order key, but am having difficulty displaying the queryset with a GET request. I am unsure why the queryset isn't being displayed and the "display: Not Found" exception is being given.

Relevant models

# Model for Sales table
class Sale(models.Model):
    sales_order = models.CharField(max_length=70, blank=False)
    model = models.ForeignKey(Model, null=True, on_delete=models.SET_NULL, related_name='sales')
    quantity = models.IntegerField(blank=False, default=1)
    customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL, related_name='sales')
    sale_id = models.IntegerField(default=1, unique=True, primary_key=True)

    class Meta:
        unique_together = [['sales_order', 'model']]
        verbose_name = 'Sale'
        verbose_name_plural = 'Sales'
        db_table = 'tbl_sales'

    def __str__(self):
        return self.sales_order

    def save(self, *args, **kwargs):
        if self._state.adding:
            last_id = Sale.objects.all().aggregate(largest=models.Max('sale_id'))['largest']
            if last_id is not None:
                self.sale_id = last_id + 1
        super(Sale, self).save(*args, **kwargs)


# Model for Serial Number table
class SerialNumber(models.Model):
    sn = models.CharField(max_length=120, blank=False, primary_key=True)
    quantity = models.IntegerField(blank=False, default=0)
    initial = models.IntegerField(blank=False, default=0)
    final = models.IntegerField(blank=False, default=0)
    brand = models.ForeignKey(Brand, null=True, on_delete=models.CASCADE, related_name='serial_numbers')
    model = models.ForeignKey(Model, null=True, on_delete=models.CASCADE, related_name='serial_numbers')
    sales_order = models.ForeignKey(Sale, null=True, on_delete=models.CASCADE, related_name='serial_numbers')
    customer = models.ForeignKey(Customer, null=True, on_delete=models.CASCADE, related_name='serial_numbers')
    for_stock = models.BooleanField()
    date_recorded = models.DateField(auto_now_add=True)
    sn_id = models.IntegerField(default=1, unique=True)

    class Meta:
        verbose_name = 'Serial Number'
        verbose_name_plural = 'Serial Numbers'
        db_table = 'tbl_serial_numbers'

    def __str__(self):
        return self.sn

    def save(self, *args, **kwargs):
        if self._state.adding:
            last_id = SerialNumber.objects.all().aggregate(largest=models.Max('sn_id'))['largest']
            if last_id is not None:
                self.sn_id = last_id + 1
        super(SerialNumber, self).save(*args, **kwargs)

Serializers

class SerialNumberSerializer(serializers.ModelSerializer):
    sales_order = SalesSerializer(many=False, read_only=True)

    brand = BrandSerializer(many=False, read_only=True)
    brand_ref = serializers.PrimaryKeyRelatedField(queryset=Brand.objects.all(), source='brand',
                                                   write_only=True)
    model = ModelNumberSerializer(many=False, read_only=True)
    model_ref = serializers.PrimaryKeyRelatedField(queryset=Model.objects.all(), source='model',
                                                   write_only=True)
    customer = CustomerSerializer(many=False, read_only=True)
    customer_ref = serializers.PrimaryKeyRelatedField(queryset=Customer.objects.all(),
                                                      write_only=True)

    class Meta:
        model = SerialNumber
        fields = [
            'sn', 'quantity', 'initial', 'final', 'brand',
            'model', 'customer', 'for_stock',
            'date_recorded', 'sn_id', 'brand_ref', 'model_ref',
            'customer_ref', 'sales_order'
        ]
        read_only_fields = ['date_recorded', 'sn_id', 'sales_order']
        lookup_field = ['sn']

class SalesSerializer(serializers.ModelSerializer):
    model = ModelNumberSerializer(many=False, read_only=True)
    model_ref = serializers.PrimaryKeyRelatedField(queryset=Model.objects.all(), source='model',
                                                   write_only=True)
    customer = CustomerSerializer(many=False, read_only=True)
    customer_ref = serializers.PrimaryKeyRelatedField(queryset=Customer.objects.all(), source='customer',
                                                      write_only=True)

    class Meta:
        model = Sale
        fields = ['sales_order', 'model', 'quantity', 'customer', 'sale_id', 'model_ref', 'customer_ref']
        read_only_fields = ['sale_id', 'model', 'customer']
        lookup_field = 'sales_order'

Code I am using for my ViewSets

# View Set for Serial Number
class SerialNumberViewSet(viewsets.ModelViewSet):
    serializer_class = SerialNumberSerializer
    queryset = SerialNumber.objects.all()


# View set for serial number lookup by sales order
class SerialNumberWSaleViewSet(viewsets.ReadOnlyModelViewSet):
    def get_queryset(self):
        if not self.kwargs:
            return SerialNumber.objects.all()
        else:
            print(SerialNumber.objects.filter(sales_order__sales_order=self.kwargs["pk"]))
            queryset = SerialNumber.objects.filter(sales_order__sales_order=self.kwargs["pk"])
            return queryset

    serializer_class = SerialNumberSerializer


# View Set for Sale
class SaleViewSet(viewsets.ModelViewSet):
    serializer_class = SalesSerializer
    queryset = Sale.objects.all()

Code I am using for my routing

router = routers.DefaultRouter()
router.register(r'brands', BrandViewSet)
router.register(r'modelNumber', ModelNumberViewSet)
router.register(r'customer', CustomerViewSet)
router.register(r'shipping', ShippingLogViewSet)
router.register('serial', SerialNumberViewSet)
router.register(r'freight', FreightViewSet)
router.register(r'user', UserViewSet)
router.register(r'sales', SaleViewSet)
router.register(r'serialWSales', SerialNumberWSaleViewSet, basename='Sale')

urlpatterns = [
    path('', views.index, name='index'),
    path('test/', TemplateView.as_view(template_name="home.html"), name='home'),
    path('api/', include(router.urls)),
]

Django Rest Framework Display Command prompt output

JSmalls
  • 51
  • 1
  • 1
    Hello, you are not doing this the proper way. What you really want to do is add filtering to the existing endpoint `serial` by adding support for a query parameter, in which case you will do something like `/serial/?sales_order=`. You can check how to do this in [docs](https://www.django-rest-framework.org/api-guide/filtering/#filtering-against-query-parameters) – Gabriel Muj Aug 09 '19 at 12:43
  • 1
    Thank you for guiding me to the proper implementation. It works exactly as I wanted it too! @GabrielMuj – JSmalls Aug 09 '19 at 16:40

0 Answers0