Reputation: 31
I have two models that form a one-to-many relationship. One pallet has multiple images associated with it.
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.
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__'
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:
class PalletDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Image.objects.prefetch_related('pallet').all()
serializer_class = ImageSerializer
Upvotes: 2
Views: 920
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
Reputation: 2470
Have you tried filter_by() method
queryset = Model.query.filter_by(id=pk).first()
Upvotes: 0
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
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