cthomas96
cthomas96

Reputation: 31

How can I create a view that retrieves all objects with matching primary key in url?

I have two models that form a one-to-many relationship. One pallet has multiple images associated with it.

models.py

class Pallet(models.Model):

    pallet_id = models.IntegerField(primary_key=True)

    def __str__(self):
        return str(self.pallet_id)

    class Meta:
        ordering = ('pallet_id',)


class Image(models.Model):

    created = models.DateTimeField(auto_now_add=True)
    pallet = models.ForeignKey(Pallet, on_delete=models.CASCADE)
    image = models.FileField(upload_to="")

    def __str__(self):
        return str(self.created)

I'm trying to create a view where I get all images associated with a particular pallet_id from the url.

serializers.py

class ImageSerializer(serializers.HyperlinkedModelSerializer):

    pallet = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Image
        fields = '__all__'

class PalletSerializer(serializers.ModelSerializer):
    class Meta:
        model = Pallet
        fields = '__all__'

urls.py

urlpatterns = [
    url(r'^pallets/', include([
        url(r'^(?P<pk>[0-9]+)/$', views.PalletDetail.as_view(), name='pallet-detail'),
        ])),
]

I think the issue is in the views.py with the PalletDetail class. I am confused on how to write the view based on the primary key from the URL. I've tried to use **kwargs['pk'] but does using this make it a function-based view? If so, would it be bad form to mix class-based and function-based views? How can I get similar behavior from class-based views?

I'm really struggling with the views here:

views.py

class PalletDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Image.objects.prefetch_related('pallet').all()
    serializer_class = ImageSerializer

Upvotes: 2

Views: 920

Answers (4)

Ken4scholars
Ken4scholars

Reputation: 6296

You're going about it the wrong way. You want to return a list of images belonging to the pallet so what you need is a list view for the images and not a pallet detail view. The url should look like this:

/pallets/<pallet_id>/images/

In this way the url is self-descriptive and by REST standards you can easily see that you are requesting for images belonging to a pallet and not the pallet itself

In urls.py

urlpatterns = [
    url(r'^pallets/', include([
        url(r'^(?P<pallet_pk>[0-9]+)/images/$', views.PalletImagesListView.as_view(), name='pallet-images-list'),
        ])),
]

In views, you have to overide the get_queryset() method, so that it only returns the images for the pallet specified

class PalletImagesListView(generics.ListAPIView):
    serializer_class = ImageSerializer

    def get_queryset(self):
        return Image.objects.prefetch_related('pallet').filter(pallet__pk=self.kwargs.get('pallet_pk'))

So now you can request the first pallet's images with /pallets/1/images/

Upvotes: 1

Nancy Moore
Nancy Moore

Reputation: 2470

Have you tried filter_by() method

queryset = Model.query.filter_by(id=pk).first()

Upvotes: 0

Aman Garg
Aman Garg

Reputation: 2547

You are using the serializer and view in a wrong way.

The problem with yours PalletDetail view is that you are using the wrong queryset. The queryset should return Pallet objects, since the lookup will be on that queryset (default lookup field is 'pk'). Also, you will then need to use the serializer for Pallet since that is supposed to handle the data for the Pallet object.

class PalletDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Pallet.objects.all()
    serializer_class = PalletSerializer

Upvotes: 0

Sangram
Sangram

Reputation: 354

In Function based view pass pk parameter example:

def Example_function(request, pk):
    queryset = Model.objects.filter(id=pk)

In Class-Based views get url parameter

pk = self.kwargs.get('pk')
queryset = Model.objects.filter(id=pk)

Upvotes: 1

Related Questions