I'm creating a comment api but when i run the server give this error:
FieldError at /
Related Field got invalid lookup: is_null
i don't know how to fix it. i'm creating a nested comment api. this is my code:
#serializer
class CommentSerializer(serializers.ModelSerializer):
loadParent = serializers.SerializerMethodField("loadPrentData")
def loadPrentData(self, comment):
comments = Comment.objects.filter(parent=comment)
comments_ser = CommentSerializer(comments, many=True).data
return comments_ser
class Meta:
model = Comment
fields = ['id', 'user', 'product', 'parent', 'body', 'created', 'loadParent']
class ProductSerializer(serializers.ModelSerializer):
comments = serializers.SerializerMethodField("loadProductComments")
def loadProductComments(self, _product):
_comments = Comment.objects.filter(product=_product, parent__is_null=True)
_comments_ser = CommentSerializer(_comments, many=True, read_only=True).data
return _comments_ser
class Meta:
model = Product
fields = ['id', 'category', 'name', 'slug', 'image_1',
'image_2', 'image_3', 'image_4', 'image_5',
'description', 'price', 'available', 'created', 'updated', 'comments']
lookup_field = 'slug'
extra_kwargs = {
'url': {'lookup_field': 'slug'}
}
#views:
#api_view()
def AddComent(request, parent_id=None):
parent = request.data.get("parent_id")
serializer = CommentSerializer(data=request.data)
if serializer.is_valid():
if parent is not None:
comment = Comment.objects.create(user=request.user, product=serializer.validated_data['product'],
parent_id=serializer.validated_data['parent'],
body=serializer.validated_data['body'])
else:
comment = Comment.objects.create(user=request.user, product=serializer.validated_data['product'],
body=serializer.validated_data['body'])
comments_ser = CommentSerializer(comment,many=False, read_only=True).data
return Response(comments_ser, status=status.HTTP_200_OK)
return Response(status=status.HTTP_400_BAD_REQUEST)
Your line
_comments = Comment.objects.filter(product=_product, parent__is_null=True)
should be
_comments = Comment.objects.filter(product=_product, parent__isnull=True)
Related
I want to filter out some instance based on the query parameter I get in the GET call.
class RevisionSerializer(serializers.ModelSerializer):
slot_info = serializers.SerializerMethodField(required=False, read_only=True)
batch_config = serializers.SerializerMethodField(required=False, read_only=True)
class Meta:
model = Revision
fields = ['id', 'status', 'revision_id', 'instructor', 'number_of_classes', 'start_date',
'slot', 'slot_info', 'tinyurl', 'zoom_link', 'batch_config']
read_only_fields = ['revision_id']
def get_batch_config(self, obj):
# filter this on the incoming data from the GET call
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=obj.revision_id)
batch_config_values = related_batches.values('batch_id', 'age_group', 'level', 'course_version', 'style__name',
'class_number')
return batch_config_values
This is my serializer and I will be passing one date and based on that date I want to filter my serializermethodfield. How can I achieve this?
You can pass parameters to a Serializer using its context:
# views.py
class RevisionView(GenericAPIView):
serializer_class = RevisionSerializer
def get_serializer_context(self):
return {'revision_id': self.request.GET.get('revision_id')}
# serializers.py
class RevisionSerializer(serializers.ModelSerializer):
def get_batch_config(self, obj):
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=self.context.get('revision_id'))
Thanks to #ThomasGth. I did it like this.
SERIALIZER
class RevisionSerializer(serializers.ModelSerializer):
slot_info = serializers.SerializerMethodField(required=False, read_only=True)
batch_config = serializers.SerializerMethodField(required=False, read_only=True,
)
class Meta:
model = Revision
# fields = '__all__'
fields = ['id', 'status', 'revision_id', 'instructor', 'number_of_classes', 'start_date',
'slot', 'slot_info', 'tinyurl', 'zoom_link', 'batch_config']
read_only_fields = ['revision_id']
def get_batch_config(self, obj):
calendar_date = self.context.get('calendar_date')
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=obj.revision_id)
if calendar_date:
related_batches = related_batches.filter(calendar_date)
batch_config_values = related_batches.values('batch_id', 'age_group', 'level', 'course_version', 'style__name',
'class_number')
return batch_config_values
VIEWSET
class RevisionViewset(viewsets.ModelViewSet):
queryset = Revision.objects.all().order_by('-modified_at').select_related('instructor', 'slot')
serializer_class = RevisionSerializer
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
filterset_class = RevisionFilter
def get_serializer_context(self):
context = {'request': self.request}
calendar_date = self.request.GET.get('calendar_date')
if calendar_date:
context['calendar_date'] = calendar_date
return context
Here is my code where I generate a PDF file, (like an invoice), but I can't retrieve the fields from the admin.TabularInline.
In my model.py I have to class: Sale and SaleItems,and in admin.py I have :
class SaleItemsInLine(admin.TabularInline):
model = SaleItems
extra = 1
readonly_fields = ('total', )
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size':'100%'})},
}
#admin.register(Sale)
class SaleAdmin(DjangoObjectActions, admin.ModelAdmin):
fields = (
('order', 'created', 'due_date'),
('profile'),
('pay_method', 'tax_card'),
('therapist' ,'activity',),
('notes'),
('totals'),
('pay', 'payOne','payTwo'),
('subtotal', 'status'),
)
readonly_fields = ('created', 'totals', 'order','subtotal', 'status', 'tax_card')
search_fields = ['profile__name', 'profile__cpf',
'profile__phone', 'activity', ]
autocomplete_fields = ('profile',)
list_display = ('profile', 'order', 'created', 'due_date', 'totals', 'status')
inlines = [SaleItemsInLine]
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size':'30'})},
models.TextField: {'widget': Textarea(attrs={'rows':4, 'cols':100})},
}
def generate_pdf(self, request, obj):
html_string = render_to_string('sales/invoice.html', {'obj': obj})
html = HTML(string=html_string, base_url=request.build_absolute_uri())
html.write_pdf(target='/tmp/{}.pdf'.format(obj), presentational_hints=True);
fs = FileSystemStorage('/tmp')
with fs.open('{}.pdf'.format(obj)) as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'filename="{}.pdf"'.format(obj)
return response
return response
I get fields from Sale with {{ obj.name }}, {{ obj.created}}, etc...
How I get the fields from SaleItems(TabulaInline) ???
I found a solution making a query inside the generate_pdf and passing as a new context:
def generate_pdf(self, request, obj):
qs = SaleItems.objects.filter(sale_id=obj.pk)
html_string = render_to_string('sales/invoice.html', {'obj': obj, 'qs': qs })
...
I want to show only two properties of the model in the list of items, but then in a specific item show all the properties
/api/character <-- show a list with name and id properties
/api/character/30 <-- show all properties of the item with id 30
Code i have in serializer.py:
class CharacterSerializer(serializers.ModelSerializer):
language = LanguageSerializer(read_only=True)
region = RegionSerializer(read_only=True)
realm = RealmSerializer(read_only=True)
faction = FactionSerializer(read_only=True)
race = RaceSerializer(read_only=True)
wow_class = ClassSerializer(read_only=True)
spec = SpecSerializer(read_only=True)
talents = TalentSerializer(many=True, read_only=True)
pvp_talents = PvpTalentSerializer(many=True, read_only=True)
covenant = CovenantSerializer(read_only=True)
soulbind = SoulbindSerializer(read_only=True)
conduits = ConduitSerializer(many=True, read_only=True)
class Meta:
model = Character
fields = ['id', 'name', 'language', 'region', 'realm', 'faction', 'race', 'wow_class', 'spec', 'talents', 'pvp_talents',
'covenant', 'covenant_rank', 'soulbind', 'soulbind_abilities', 'conduits', 'item_level', 'media', 'avatar', 'rating_2v2',
'rating_3v3', 'rating_rbg', 'max_2v2', 'max_3v3', 'max_rbg', 'achievement_points', 'account_achievements', 'seasons',
'alters', 'date_added', 'last_search', 'checked']
code in views.py
class CharacterViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CharacterSerializer
permission_classes = []
queryset = Character.objects.all()
filter_backends = [filters.SearchFilter, DjangoFilterBackend]
search_fields = ['name']
filterset_fields = ['language', 'region', 'realm', 'faction', 'race', 'wow_class', 'spec', 'covenant', 'soulbind']
Thx a lot!
Solved.
I have created two serializer for the model one for list and another for detail
class TalentSerializer(serializers.ModelSerializer):
class Meta:
model = Talent
fields = ['id', 'name']
class TalentDetailSerializer(serializers.ModelSerializer):
language = LanguageSerializer(read_only=True)
wow_class = ClassSerializer(read_only=True)
spec = SpecSerializer(many=True, read_only=True)
class Meta:
model = Talent
fields = ['id', 'name', 'language', 'description', 'spell_id', 'talent_id', 'wow_class', 'spec', 'tier_index', 'column_index', 'level', 'icon']
in the viewset I have redefined the get of the class:
class TalentViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = TalentSerializer
permission_classes = []
queryset = Talent.objects.all()
filter_backends = [filters.SearchFilter, DjangoFilterBackend]
search_fields = ['name']
filterset_fields = ['language', 'spell_id', 'talent_id', 'wow_class', 'spec', 'tier_index', 'column_index', 'level']
def get_serializer_class(self):
if self.action == 'retrieve':
return TalentDetailSerializer
return TalentSerializer
Now works well /api/talent return a list with id and name of items and /api/talent/id return the item with all props of model :)
I am newer in Django rest api. My code is bellow:
class PatientViewSet(viewsets.ModelViewSet):
queryset = Patient.objects.all()
serializer_class = PatientSerializer
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
filterset_fields = ['id', 'email', 'mobile', 'status', 'type', 'gender']
ordering_fields = ['id', 'name']
def get_queryset(self):
queryset = Patient.objects.all()
status = self.request.query_params.get('status')
name = self.request.query_params.get('name')
if not status:
queryset = queryset.exclude(status="DELETE")
if name:
queryset = queryset.filter(name__icontains=name)
return queryset
def retrieve(self, request, pk=None):
queryset = Patient.objects.all()
patient = get_object_or_404(queryset, pk=pk)
serializer = PatientSerializer(patient)
summary = dict()
summary['payment'] = list(PatientPayment.objects.filter(patient_id=pk).aggregate(Sum('amount')).values())[0]
summary['appointment'] = DoctorAppointment.objects.filter(patient_id=pk).count()
d_appoint = DoctorAppointment.objects.filter(patient__id=pk).last()
appoint_data = DoctorAppointmentSerializer(d_appoint)
summary['last_appointment'] = appoint_data
content = {"code": 20000, "data": serializer.data, "summary": summary}
return Response(content)
Here url is:
http://127.0.0.1:8000/api/patients/2/
When I run in postman it getting the error bellow:
TypeError at /api/patients/2/
Object of type 'DoctorAppointmentSerializer' is not JSON serializable
Here problem with the code snippet:
d_appoint = DoctorAppointment.objects.filter(patient__id=pk).last()
appoint_data = DoctorAppointmentSerializer(d_appoint)
My question is how can I getting my result?
DoctorAppointmentSerializer Class:
class DoctorAppointmentSerializer(serializers.HyperlinkedModelSerializer):
patient = PatientSerializer(read_only=True)
patient_id = serializers.IntegerField()
doctor = DoctorSerializer(read_only=True)
doctor_id = serializers.IntegerField()
doc_image = Base64ImageField(
allow_null=True, max_length=None, use_url=True, required=False
)
doc_file = Base64ImageField(
allow_null=True, max_length=None, use_url=True, required=False
)
class Meta:
model = DoctorAppointment
fields = ['id', 'name', 'mobile', 'problem', 'age', 'gender', 'description', 'doctor', 'doctor_id', 'patient',
'patient_id', 'advice', 'doc_image', 'doc_file', 'created_at']
You have to call the .data property of DoctorAppointmentSerializer class
appoint_data = DoctorAppointmentSerializer(d_appoint).data
^^^^^^
Dog model has a field "cat'
class Dog(models.Model):
...
cat = models.ForeignKey(Cat)
...
class CatSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Cat
# Replace ID with SLUG in urls
lookup_field = 'slug'
fields = ('url', 'slug')
extra_kwargs = {
'url': {'lookup_field': 'slug'}
}
class DogSerializer(serializers.HyperlinkedModelSerializer):
cat= serializers.HyperlinkedRelatedField(
view_name='cat-detail',
lookup_field='slug',
many=False,
read_only=True
)
class Meta:
model = Dog
fields = ('url', 'slug', 'cat')
lookup_field = 'slug'
extra_kwargs = {
'url': {'lookup_field': 'slug'}
}
class CatViewSet(viewsets.ModelViewSet):
def get_serializer_context(self):
context = super().get_serializer_context()
context['slug'] = self.kwargs.get('slug')
return context
queryset = Cat.objects.all()
serializer_class = CatSerializer
lookup_field = 'slug'
class DogViewSet(viewsets.ModelViewSet):
queryset = Dog.objects.all()
lookup_field = 'slug'
serializer_class = DogSerializer
router = routers.DefaultRouter()
router.register(r'cats', rest_views.CatViewSet)
router.register(r'dogs', rest_views.DogViewSet)
How can I set:
read_only=False
The error I get when I set it to False is:
'Relational field must provide a queryset argument, '
AssertionError: Relational field must provide a queryset argument, override get_queryset, or set read_only=True.
cat= serializers.HyperlinkedRelatedField(
view_name='cat-detail',
lookup_field='slug',
many=False,
read_only=False,
queryset=Cat.objects.all()
)
This worked just fine.