This is my serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
img_count = serializers.SerializerMethodField('get_img_count')
post_count = serializers.SerializerMethodField('get_post_count')
msg_count = serializers.SerializerMethodField('get_msg_count')
class Meta:
model = User
fields = ('id', 'username', 'img_count', 'post_count', 'msg_count')
def get_img_count(self, obj):
try:
img_data = ImgSerializer(Img.objects.filter(author=obj.id), many=True)
except img_data.DoesNotExist:
return 0
return img_data
def get_post_count(self, obj):
try:
post_data = PostSerializer(Post.objects.filter(author=obj.id), many=True)
except post_data.DoesNotExist:
return 0
return post_data
def get_msg_count(self, obj):
try:
msg_data = Smessage(Msg.objects.filter(author=obj.id), many=True)
except msg_data.DoesNotExist:
return 0
return msg_data
This is my views.py
class UserProfile(APIView):
permission_classes = [AllowAny]
def get(self, request):
query = User.objects.all()
serializer = UserProfileSerializer(query, many=True)
return Response(serializer.data)
This is the Error Snippet
I want to get this
{
"id": 9,
"username": "emil#gmail.com",
"img_count:3,
"post_count":5,
"msg_count":50,
}
also getting error after using img_count.count().
You should change the exceptions to:
img_data.DoesNotExist --> Img.DoesNotExist
post_data.DoesNotExist --> Post.DoesNotExist
msg_data.DoesNotExist --> Msg.DoesNotExist
Because, instances does not have any exception object, rather the model classes has them. More information can be found in documentation.
Update
If you just want the count, then you don't need to use such extensive implementation. You can simply try:
def get_img_count(self, obj):
return Img.objects.filter(author=obj.id).count()
def get_post_count(self, obj):
return Post.objects.filter(author=obj.id).count()
def get_msg_count(self, obj):
return Msg.objects.filter(author=obj.id).count()
You should set default value of each variable because in case of error other than DoesNotExist, you will face this error.
class UserProfileSerializer(serializers.ModelSerializer):
img_count = serializers.SerializerMethodField('get_img_count')
post_count = serializers.SerializerMethodField('get_post_count')
msg_count = serializers.SerializerMethodField('get_msg_count')
class Meta:
model = User
fields = ('id', 'username', 'img_count', 'post_count', 'msg_count')
def get_img_count(self, obj):
img_data = 0
try:
img_data = ImgSerializer(Img.objects.filter(author=obj.id), many=True).data
except Img.DoesNotExist:
pass
return img_data
def get_post_count(self, obj):
post_data = 0
try:
post_data = PostSerializer(Post.objects.filter(author=obj.id), many=True).data
except Post.DoesNotExist:
pass
return post_data
def get_msg_count(self, obj):
msg_data = 0
try:
msg_data = Smessage(Msg.objects.filter(author=obj.id), many=True).data
except Msg.DoesNotExist:
pass
return msg_data
Related
I have a main serializer, and I also have a serializer for my BOOK model so I made a method to return a serialized queryset using my BOOK SERIALIZER
BUT the problem is ** I can't access my main serializer context through BookSerializer**
What can I do?
Views.py:
class BookMainPage(ListModelMixin, RetrieveModelMixin, GenericViewSet):
queryset = Book.objects.select_related('owner').all()
def get_serializer_context(self):
return {'user': self.request.user, 'book_id': self.kwargs.get('pk'), 'request': self.request}
def get_serializer_class(self):
if self.kwargs.get('pk') is None:
return MainPageSerializer
return BookComplexSerializer
MainPageSerializer:
class MainPageSerializer(serializers.Serializer):
#staticmethod
def get_new_books(self):
return BookSimpleSerializer(Book.objects.all().order_by('-created_at')[:10], many=True).data
#staticmethod
def get_popular_books(self):
return BookSimpleSerializer(Book.objects.all().order_by('-bookRate')[:10], many=True).data
#staticmethod
def get_most_borrowed(self):
return BookSimpleSerializer(Book.objects.all().order_by('-wanted_to_read')[:10], many=True).data
new_books = serializers.SerializerMethodField(method_name='get_new_books')
popular_books = serializers.SerializerMethodField(method_name='get_popular_books')
most_borrowed_books = serializers.SerializerMethodField(method_name='get_most_borrowed')
BookSimpleSerializer:
class BookSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'picture']
def get_picture(self, obj: Book):
request = self.context['request']
photo_url = obj.picture.url
return request.build_absolute_uri(photo_url)
picture = serializers.SerializerMethodField(method_name='get_picture')
class CategorySimpleSerializer(serializers.ModelSeria
You can intiialiaze your serializer passing a context with your request in the MethodField method:
class MainPageSerializer(serializers.Serializer):
def get_new_books(self):
return BookSimpleSerializer(
Book.objects.all().order_by('-created_at')[:10],
many=True,
context={"request": self.context["request"]}
).data
def get_popular_books(self):
return BookSimpleSerializer(
Book.objects.all().order_by('-bookRate')[:10],
many=True,
context={"request": self.context["request"]}
).data
def get_most_borrowed(self):
return BookSimpleSerializer(
Book.objects.all().order_by('-wanted_to_read')[:10],
many=True,
context={"request": self.context["request"]}
).data
new_books = serializers.SerializerMethodField(method_name='get_new_books')
popular_books = serializers.SerializerMethodField(method_name='get_popular_books')
most_borrowed_books = serializers.SerializerMethodField(method_name='get_most_borrowed')
And i remove the staticmethod decorator. Your method does not have to be static
serializers.py
class Product_Serializers(serializers.ModelSerializer):
product_id = serializers.CharField(required=False)
class Meta:
model = Product
fields = ('product_id','product_name',)
class Clientpost_Serializers(serializers.ModelSerializer):
billing_method = Billingmethod_Serializers()
product = Product_Serializers(many=True)
def create(self, validated_data):
billing_method_data = validated_data.pop('billing_method')
product_data = validated_data.pop('product')
billing_method = Billing_Method.objects.create(**billing_method_data)
validated_data['billing_method'] = billing_method
client = Client.objects.create(**validated_data)
product = [Product.objects.create(**product_data) for product_data in product_data]
client.product.set(product)
return client
def update(self, instance, validated_data):
billing_method_data = validated_data.pop('billing_method')
billing_method = instance.billing_method
instance.currency = validated_data.get('currency', instance.currency)
instance.currency_type = validated_data.get('currency_type', instance.currency_type)
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.description = validated_data.get('description', instance.description)
instance.street_address = validated_data.get('street_address', instance.street_address)
instance.city = validated_data.get('city', instance.city)
instance.state = validated_data.get('state', instance.state)
instance.country = validated_data.get('country', instance.country)
instance.pincode = validated_data.get('pincode', instance.pincode)
instance.industry = validated_data.get('industry', instance.industry)
instance.company_size = validated_data.get('company_size', instance.company_size)
instance.client_name = validated_data.get('client_name', instance.client_name)
instance.contact_no = validated_data.get('contact_no', instance.contact_no)
instance.mobile_no = validated_data.get('mobile_no', instance.mobile_no)
instance.email_id = validated_data.get('email_id', instance.email_id)
instance.client_logo = validated_data.get('client_logo', instance.client_logo)
instance.client_code = validated_data.get('client_code', instance.client_code)
instance.save()
billing_method.billing_name = billing_method_data.get('billing_name', billing_method.billing_name)
billing_method.save()
product = validated_data.get('product')
for prod in product:
product_id = prod.get('product_id', None)
if product_id:
product_data = Product.objects.get(product_id=product_id, product=instance)
product_data.product_name = prod.get('product_name', product_data.product_name)
product_data.save()
else:
Product.objects.create(product=instance, **prod)
return instance
class Meta:
model = Client
fields = ('client_id','currency','currency_type','billing_method','first_name',...)
When I Tired to do POST and PUT method it is getting posted and updated successfully. But it is getting created everytime when I do POST, as I have given unique=True so it is throwing the product is already exist. But I dont need to create each time, if it is already available it need to be saved in the nested model field. If that is possible ?
I tried and I couldn't able to figure it out, please help me to solve the issue. It would be a life saver if I could get any answer.
Views.py
class Clientlist(APIView):
renderer_classes = (CustomRenderer,)
parser_classes = [parsers.MultiPartParser, parsers.FormParser]
"""
List all snippets, or create a new snippet.
"""
def get(self, request, format=None):
clients = models.Client.objects.all()
serializer = serializers.Clientpost_Serializers(clients, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = serializers.Clientpost_Serializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ClientDetail(APIView):
renderer_classes = (CustomRenderer,)
parser_classes = [parsers.MultiPartParser, parsers.FormParser]
def get_object(self, pk):
try:
return models.Client.objects.get(pk=pk)
except models.Client.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
client = self.get_object(pk)
serializer = serializers.Client_Serializers(client)
return Response(serializer.data)
def put(self, request, pk, format=None):
client = self.get_object(pk)
serializer = serializers.Clientpost_Serializers(client, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
client = self.get_object(pk)
client.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
This is the problem: I have a serializer field pointing to another serializer. I sending an allright request to server and I get this response:
{
"purchase_header": [
"This field is required."
]
}
But the field was sended by POST request (in debugger I can see it).
I finded this code in html.py (from DRF):
def parse_html_dict(dictionary, prefix=''):
"""
Used to support dictionary values in HTML forms.
{
'profile.username': 'example',
'profile.email': 'example#example.com',
}
-->
{
'profile': {
'username': 'example',
'email': 'example#example.com'
}
}
"""
ret = MultiValueDict()
regex = re.compile(r'^%s\.(.+)$' % re.escape(prefix))
for field in dictionary:
match = regex.match(field)
if not match:
continue
key = match.groups()[0]
value = dictionary.getlist(field)
ret.setlist(key, value)
return ret
Well, when debuging I can see that prefix variable contain "purchase_header" and field variable contain the same "purchase_header" string but de match fail returning None. Very rare... dictionary parameter contain all keys and values.
But If you can helpme I appreciate much.
This is the rest of significant code:
urls.py
router = DefaultRouter()
router.register(r'cancel-requests', PurchaseCancellationsRequestViewSet,
basename='purchase-cancel-requests')
router.register(r'invoices', PurchaseViewSet, basename='purchase')
urlpatterns = router.urls
urlpatterns += [path('payment-headers/', PaymentHeadersListAPIView.as_view(
), name='PaymentHeadersListAPIView')]
api.py
class PurchaseViewSet(viewsets.ModelViewSet):
"""
A viewset for viewing and editing purchases instances.
"""
serializer_class = PurchaseSerializer
queryset = Purchase.objects.all().order_by('-created_at')
permission_classes = (IsAuthenticated,)
serializer_action_classes = {
'list': PurchaseSerializer,
'create': PurchaseSerializer,
'retrieve': PurchaseSerializer,
'update': PurchaseSerializer,
'partial_update': PurchaseSerializer,
'destroy': PurchaseSerializer
}
def get_serializer_class(self):
try:
return self.serializer_action_classes[self.action]
except (KeyError, AttributeError):
return super().get_serializer_class()
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs["context"] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_list_queryset(self):
try:
store = Store.objects.get(my_owner=self.request.user)
except EmptyResultSet as e:
print("Data Error: {0}".format(e))
urlquery = self.request.GET.get('cancelled', '')
cancelled = False
if urlquery == 'true':
cancelled = True
elif urlquery == '':
# return all
return Purchase.objects.filter(created_for=store)
return Purchase.objects.filter(cancelled=cancelled, created_for=store)
def put(self, request, *args, **kwargs):
if request.user.is_seller:
raise PermissionDenied(
detail='Only owners can cancellate Purchases')
# seller create invoice cancellation request
return self.update(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
request.data['created_by'] = request.user.pk
print(request.data)
if request.user.is_owner is True:
try:
request.data['created_for'] = Store.objects.get(
my_owner=request.user).pk
except Exception as e:
print(e)
return Response(data='User has no Store associated',
status=status.HTTP_400_BAD_REQUEST)
else:
try:
request.data['created_for'] = request.user.seller_profile \
.my_store.pk
except Exception as e:
print(e)
return Response(data='User has no Store associated',
status=status.HTTP_400_BAD_REQUEST)
return self.create(request, *args, **kwargs)
def list(self, request, *args, **kwargs):
# TODO: date ranges
if self.request.user.is_seller:
# TODO: Change -> Indeed the seller can get his own created
# purchases and refactor this to method
raise PermissionDenied(
detail='Only owners can get purchase list.')
queryset = self.get_list_queryset()
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
serializers.py
from rest_framework import serializers
from .models import Purchase, PurchaseCancellationRequest, PurchaseHeader
class PurchaseHeaderSerializer(serializers.ModelSerializer):
class Meta:
model = PurchaseHeader
fields = ['id', 'name']
extra = {
'id': {'read_only': True},
'name': {'read_only': True}
}
class PurchaseSerializer(serializers.ModelSerializer):
purchase_header = PurchaseHeaderSerializer()
class Meta:
model = Purchase
fields = ['id', 'cancelled', 'created_at', 'created_by',
'created_for', 'pic', 'total_amount', 'purchase_header']
extra = {
'cancelled': {'read_only': True},
'created_at': {'read_only': True},
'id': {'read_only': True}
}
def validate_total_amount(self, value):
"""
Sanitize the amount value.
:return: total_amount as float
"""
total_amount = None
try:
total_amount = float(value)
except Exception as e:
print(e)
if total_amount:
return value
else:
raise serializers.ValidationError('Exists an error with '
'total_amount value, probably '
'an empty param or bad float '
'format')
def validate_cancelled(self, value):
"""
Sanitize the cancelled value.
:return: cancelled as python boolean
"""
cancelled = None
try:
cancelled = False if value == 'false' else True
except Exception as e:
print(e)
if cancelled:
return value
else:
raise serializers.ValidationError('Exists an error with '
'cancelled value, probably an '
'empty param or bad boolean '
'value')
def create(self, validated_data):
payment_header_pk = validated_data.pop('purchase_header')
payment_header_obj = PaymentHeader.objects.get(pk=payment_header_pk)
purchase_obj = Purchase.objects.create(
payment_header=payment_header_obj, **validated_data)
return purchase_obj
class PurchaseCancellationRequestSerializer(serializers.ModelSerializer):
class Meta:
model = PurchaseCancellationRequest
fields = ['purchase']
models.py
class PurchaseHeader(SoftDeleteModel):
name = models.CharField(max_length=50)
city = models.ManyToManyField(City, through='purchases.ProviderCity')
created_at = models.DateTimeField(default=timezone.now(), editable=False)
modified_at = models.DateTimeField(default=timezone.now())
class ProviderCity(SoftDeleteModel):
city = models.ForeignKey(City, on_delete=models.PROTECT)
purchase_header = models.ForeignKey(PurchaseHeader,
on_delete=models.PROTECT)
class Meta:
unique_together = ('city', 'purchase_header')
Thank for all friends!!
I have following serializer:
class ClientSerializer(serializers.ModelSerializer):
projects_count = serializers.ReadOnlyField()
currency = CurrencySerializer(read_only=True)
class Meta:
model = Client
fields = ('id', 'owner', 'name', 'icon_color', 'projects_count', 'hourly_rate', 'currency', )
def get_projects_count(self, obj):
if hasattr(obj, 'projects_count'):
return obj.projects_count
return 0
And this is the view for getting and creating Client objects:
class ClientListView(APIView):
http_method_names = ['get', 'post']
authentication_classes = (authentication.SessionAuthentication, )
permission_classes = [IsAuthenticated]
def post(self, request, format=None):
serializer = ClientSerializer(
context=dict(request=request),
data=request.data
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get(self, request, format=None):
qs_clients = Client.objects.filter(
owner=request.user,
).annotate(
projects_count=Count('project'),
)
client_serializer = ClientSerializer(
qs_clients,
many=True,
)
data = dict(
clients=client_serializer.data,
)
return Response(
data,
status=status.HTTP_200_OK,
)
When calling POST, data returned does not contain project_count field:
POST:
{"id":9,"owner":1,"name":"zzz xxx","icon_color":"a45ac8","hourly_rate":null,"currency":null}
But for GET, there is everything ok:
GET:
{"clients":[{"id":9,"owner":1,"name":"zzz xxx","icon_color":"a45ac8","projects_count":0,"hourly_rate":null,"currency":null}]}
I need to have projects_count included in the POST response. Why is it missing?
Thanks!
Intead of serializers.ReadOnlyField() try to use serializers.SerializerMethodField() which is already a read-only field
class ClientSerializer(serializers.ModelSerializer):
projects_count = serializers.SerializerMethodField()
# ^^^^^^^^^^
currency = CurrencySerializer(read_only=True)
class Meta:
model = Client
fields = ('id', 'owner', 'name', 'icon_color', 'projects_count', 'hourly_rate', 'currency', )
def get_projects_count(self, obj):
if hasattr(obj, 'projects_count'):
return obj.projects_count
return 0
hi i have create an Crud function for evaluation Test but i am getting keyerror 'request' this kind of strange to me i have not seen this error before i am new to django can somebody help me to fix it?
def validate(self, data, *args, **kwargs):
questions = self.context['request'].data.get("questions")
if not questions:
raise serializers.ValidationError("questions are required")
if self.context["request"].method == "POST":
self.questions = QuestionSerializer(data=questions, many=True)
self.questions.is_valid(raise_exception=True)
elif self.context["request"].method == "PUT":
self.questions = questions
self.new_questions = self.context["request"].data.get(
"new_questions")
if self.new_questions:
self.new_questions = QuestionSerializer(
data=self.new_questions, many=True)
self.new_questions.is_valid(raise_exception=True)
return data
def create(self, data):
evaluation_test = EvaluationTest()
evaluation_test.category = data['category']
evaluation_test.admin = data['admin']
evaluation_test.title = data['title']
evaluation_test.type = data['type']
evaluation_test.save()
for question in data['questions']:
question.evaluationtest = evaluation_test
question.save()
return evaluation_test
def update(self, instance, validated_data):
instance.title = validated_data.get["title", instance.title]
instance.type = validated_data.get["type", instance.type]
instance.category = validated_data.get["category", instance.category]
instance.admin = validated_data.get["admin", instance.admin]
for question in self.questions:
q = QuestionSerializer(instance=question["id"], data=question)
q.is_valid(raise_exception=True)
q.save()
if self.new_questions:
new_questions = self.new_questions.save()
for question in new_questions:
question.save()
return instance
views.py
Here is my view.py code when i am implementing the whole crud application you can see and please give me how can i modify to make it work
class EvaluationTestViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated, )
serializer_class = EvaluationTestSerializer
queryset = EvaluationTest.objects.all()
#action(methods=['get'], detail=False, url_path='by-category/(?P<category_id>\d+)', url_name='by_category')
def by_category(self, request, *args, **kwargs):
evaluationtest = EvaluationTestSerializer.by_category(
kwargs['category_id'])
if evaluationtest:
return Response(evaluationtest)
return Response(status=HTTP_404_NOT_FOUND)
def create(self, request):
serializer = EvaluationTestSerializer(data=request.data)
if serializer.is_valid():
evaluationtest = serializer.create(request)
print(evaluationtest)
if evaluationtest:
return Response(status=HTTP_201_CREATED)
return Response(status=HTTP_400_BAD_REQUEST)
you have to set the request in the serializer context.
change your create method:
def create(self, request):
serializer = EvaluationTestSerializer(data=request.data, context={'request': request})
if serializer.is_valid():
# call save() instead of create
evaluationtest = serializer.save()
print(evaluationtest)
# ideally you should also return serializer.data
return Response(status=HTTP_201_CREATED)
# ideally you should also return serializer.errors
return Response(status=HTTP_400_BAD_REQUEST)