I can't get url to be returned when I use it in a HyperlinkedModelSerializer.
# models.py
class Promotion(TimeStampedMixin, models.Model):
name = models.CharField(max_length=300)
# ...
# views.py
class PromotionViewSet(viewsets.ModelViewSet):
serializer_class = PromotionSerializer
queryset = Promotion.objects.all()
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance, context={'request': request})
return Response(serializer.data)
# serializers.py
class PromotionSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedRelatedField(
view_name="campaigns:promotion-detail", read_only=True
)
class Meta:
model = Promotion
fields = (
"url",
"id",
"name",
)
The JSON output I receive when querying curl -X GET http://localhost/api/promotion/2/:
{"id":2,"name":"My promotion"}
If I use reverse to check if the view_name in the HyperlinkedRelatedField exists, it prints the correct URL.
My question is: why doesn't the url show up in the response? It works any all my other views (comparing code with classes that works hasn't helped). Read the DRF documentation but I see nothing new (using version 3.11.0)
To get the url representation to the current object you should use the HyperlinkedIdentityField
class PromotionSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name="campaigns:promotion-detail", read_only=True
)
class Meta:
model = Promotion
fields = (
"url",
"id",
"name",
)
Related
I want to store an array in my database. For that I use ArrayType of this type in my model: [[[0.29, 10.27]]]. I would like to use a serializer to create my GET, POST and PUT requests.
Here is my model:
models.py
class Area(models.Model):
osm = ArrayField(
ArrayField(
ArrayField(
models.FloatField(),
size=2,
),
),
)
Here is my serializer :
serializer.py
class AreaSerializer(serializers.ModelSerializer):
class Meta:
model = Area
fields = ['osm', ]
And here is my view :
views.py
class ShopAreaList(ShopCustomListView):
"""Get or create areas for a shop"""
queryset = Shop.objects.all()
lookup_field = 'path'
def get(self, request, path):
"""Depends on mustBeLogged to get areas of a shop"""
shop = self.get_object()
areas = Area.objects.filter(shop=shop)
serializer = AreaSerializer(areas, many=True)
return Response(serializer.data)
def post(self, request, path):
"""For admin or shop owner to create areas"""
shop = self.get_object()
serializer = AreaSerializer(data=request.data)
if serializer.is_valid():
serializer.save(shop=shop)
return Response(serializer.data)
return Response(serializer.errors)
Here is the data I get:
{
"osm": [[[0.29, 10.27]]]
}
When I try to run my POST method I get this error:
Error binding parameter 0 - probably unsupported type.
I don't know what can I do to fix this error.
Thank you in advance for your help
I got AttributeError when attempting to get a value for field client on serializer ClientSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the QuerySet instance.
models.py
class Box(models.Model):
box = models.IntegerField()
controller = models.ForeignKey(Controller, related_name='boxes', on_delete=models.CASCADE)
def __str__(self):
return str(self.box)
class Client(models.Model):
client = models.CharField(max_length=30)
cpf = models.IntegerField()
box = models.OneToOneField(
Box,
on_delete=models.CASCADE,
primary_key=True
)
def __str__(self):
return self.client
serializers.py
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = [
"id",
"client",
"cpf",
"box",
]
class BoxSerializer(serializers.ModelSerializer):
class Meta:
model = Box
fields = [
"id",
"box",
"controller"
]
views.py
class ClientViewSet(viewsets.ModelViewSet):
serializer_class = ClientSerializer
queryset = Client.objects.all()
def list(self, request, store_pk=None, locker_pk=None, controller_pk=None, box_pk=None):
queryset = Client.objects.filter(box=box_pk, box__controller=controller_pk, box__controller__locker=locker_pk, box__controller__locker__store=store_pk)
serializer = ClientSerializer(queryset, context={'request': request})
return Response(serializer.data)
def retrieve(self, request, store_pk=None, locker_pk=None, controller_pk=None, box_pk=None):
queryset = Client.objects.filter(box=box_pk, box__controller=controller_pk, box__controller__locker=locker_pk, box__controller__locker__store=store_pk)
client = get_object_or_404(queryset)
serializer = ClientSerializer(client, context={'request': request})
return Response(serializer.data)
I'm trying to get the object client on lockers/1/controllers/1/boxes/1/client/
which is OneToOneField relations with boxes and It's in a nested router
I already tried use decorator #action but yet didn't work.
Anyone know why it's not finding the correct object attribute ?
For a list method you should use many=True parameter when you're creating a new serializer instance:
serializer = ClientSerializer(queryset, context={'request': request}, many=True)
In case of retrieve only one object should be received. Instead of
client = get_object_or_404(queryset)
you should call first(), last() (or most basically and clearly - .get(pk=pk)) on queryset to retrieve only one item from QuerySet. Then you should just execute:
# client is one of elements of your queryset
serializer = ClientSerializer(client, context={'request': request})
I need to retrieve a filtered set of data by calling an HTTP request using Django rest framework.
here are my API codes:
urls.py
urlpatterns = [
path('api/get_products/', views.get_products),
]
Views.py
#api_view(["GET", ])
def get_products(request):
category_name = request.data['category_name']
category_obj = Category.objects.get(name=category_name)
products_list = Product.objects.filter(category=category_obj)
serializer = ProductSerializers(products_list)
return Response(serializer.data)
and finally the serialierz.py
class CategorySerializers(serializers.HyperlinkedModelSerializer):
class Meta:
model = Category
fields = ['name', 'id']
class ProductSerializers(serializers.HyperlinkedModelSerializer):
category = CategorySerializers()
class Meta:
model = Product
fields = '__all__'
and am trying to call it using a get request with the argument: {'category_name':'the_name_of_the_category' }
and it returns this error:
KeyError at /categories/api/api/get_products/
'category_name'
Your API method is a GET method. You cannot accept body with get method. You can change your API method with POST method or better one, you can get 'category_name' with url. You can add url variable like that:
path('api/get_products/<slug:category_name>', views.get_products),
and your view method:
def get_products(request,category_name):
category_obj = Category.objects.get(name=category_name)
products_list = Product.objects.filter(category=category_obj)
serializer = ProductSerializers(products_list)
return Response(serializer.data)
I am trying to update my data in 'VoterList' model by using PUT api, but i don't know which function should i use in my 'views.py' file to handle the coming PUT request because in PUT api, we use parameters from URL to pick the relevent entry from model for updation and then update it by using data received from PUT api.
model.py
class VoterList(models.Model):
# id = models.IntegerField(auto_created= True, primary_key=True)
name = models.CharField( max_length=20)
email = models.EmailField()
mobile = models.IntegerField()
city = models.CharField( max_length=20)
type = models.CharField(max_length=20)
def __str__(self):
return self.name
serializers.py
class FillVoterListSerializers(serializers.HyperlinkedModelSerializer):
class Meta:
model = VoterList
fields = ('id','name', 'email', 'mobile', 'city', 'type')
def update(self, instance, validated_data):
instance.name = validated_data.pop("name", instance.name)
instance.email = validated_data.pop("email", instance.email)
instance.save()
return instance
I will manage the code for PUT in serializers by myself.
views.py
class UpdateVoter(APIView):
serializer_class = FillVoterListSerializers
permission_classes = (AllowAny,)
def post(self, request,*args,**kwargs):
isDataExist = VoterList.objects.get(id=request.data.get('id'))
if not isDataExist:
return Response({"message":"No Voter exist with this id."})
else:
isDataUpdated = self.serializer_class(isDataExist, request.data, partial=True)
if isDataUpdated.is_valid():
isDataUpdated.save()
return Response({"message": "Voter updated."})
else:
return Response({"message": "All fields are Mandatory."})
urls.py
urlpatterns = [
url('api/updateVoter/(?P<id>[0-9]+)/$', UpdateVoter.as_view(), name= "updateVoter")]
So what code should i write in my view.py to handle the PUT request.
Note: I want to tell you that i am preparing api for mobile applications, so please respond accordingly.
Any help is appreciated.
You can use the put() function in your view similar to the post() which you've used
def put(self, request, pk, format=None):
# Your code here
Refer the DRF docs : https://www.django-rest-framework.org/tutorial/3-class-based-views/
Let's say I have three models as:
class User(AppModel):
name = models.CharField(max_length=255)
class Business(AppModel):
owner = models.ForeignKey("User", related_name="businesses", on_delete=models.CASCADE)
legal_name = models.CharField(max_length=255)
class Invoice(AppModel):
business = models.ForeignKey("Business", related_name="invoices", on_delete=models.CASCADE)
amount = models.integerField()
As you can see, a user can have multiple businesses and a business can have multiple invoices.
My serializers.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields= ('name')
class BusinessSerializer(serializers.ModelSerializer):
owner = UserSerializer(many=False)
class Meta:
model = Business
fields= ('owner','legal_name')
class InvoiceSerializer(serializers.ModelSerializer):
business= BusinessSerializer(many=False)
class Meta:
model = Invoice
fields= ('business','amount')
views.py:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class BusinessViewSet(viewsets.ModelViewSet):
queryset = Business.objects.all()
serializer_class = BusinessSerializer
class InvoiceViewSet(viewsets.ModelViewSet):
queryset = Invoice.objects.all()
serializer_class = InvoiceSerializer
urls.py:
router = DefaultRouter()
router.register('user', UserViewSet, base_name='users')
router.register('business', BusinessViewSet, base_name='businesses')
router.register('invoice', InvoiceViewSet, base_name='invoices')
urlpatterns = router.urls
http://example.com/api/user returns all users. Not a problem.
But the functionality I'm looking for is:
http://example.com/api/business/ returns
[
{
"legal_name": "1business",
"owner": 1,
},
{
"legal_name": "2business",
"owner": 1,
},]
http://example.com/api/business/1/ returns
{
"legal_name": "1business",
"owner": 1,
}
The above is ok. But I also need:
http://example.com/api/business/1/invoices/ should return
[
{
"business": 1,
"amount": 100,
},
{
"business": 1,
"amount": 999,
},]
As well I should be able to create update delete those invoices there.
Any Help? I'm new to django rest framework. The above classes are just a sample. Ignore errors.
You should use django decorators which are #list_route and #detail_route for your viewset. But be careful with your DRF version. Because those decorators merged together as #action in DRF 3.8+. Here is the announcement.
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
class BusinessViewSet(viewsets.ModelViewSet):
queryset = Business.objects.all()
serializer_class = BusinessSerializer
#action(detail=True, methods=["GET"], url_path="invoices")
def invoices(self, request, pk=None):
"""
Your codes comes here to return related result.
pk variable contains the param value from url.
if you do not specify the url_path properties then action will accept the function's name as url path.
"""
entity = Invoice.objects.filter(business=pk)
serializer = self.get_serializer(entity, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Then, you will be able to call this endpoints from;
http://example.com/api/business/{{PK}}/invoices/
http://example.com/api/business/1/invoices/
http://example.com/api/business/3/invoices/
http://example.com/api/business/23/invoices/
Here you can find more details about #actions from documentation.
PS: Don't forget to control empty entity results in your codes. You should return correct response with correct status codes.