Serializer data is not showing on the API - django

Hey Guys this is my first project in Django, I am trying to get my 'foreign keys' field into my API with Django Rest framework.
I am trying to do a Post a product. since i cannot see input fields i am stuck here.
It might be something very simpel, i might didn’t see it.
*******UPDATE********
As requested, have put an image here for more details of what i actually want to achieve.
In the image below is what i WANT in my api to show and i do get it like this, all my field like how i want them (apart from that i get category twice , one in digits also)
But if u take a closer look down below, the POST form is limited to the attributes of the product Model class itself. So i can not do an actual post from the frontend side.
in the serializers
If i comment the fields out i do get down below my fields to POST, yeah.. but When i post i get digits in my API rather than the names of the foreign keys
So notice i get all the field that i need for my frontend in order to handle the post function. But then i get digits in the api instead
I hope i made it more clear than before.. :)
Thank you in advance
serializers.py
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from .models import *
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'password')
extra_kwargs = {'password':{'write_only':True,'required':True}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
print(user)
Token.objects.create(user=user)
return user
class ProductSerializer(serializers.ModelSerializer):
product_id = serializers.CharField(source='product.url', read_only=True)
category_name = serializers.CharField(source='category.name', read_only=True)
user_id = serializers.CharField(source='user.id', read_only=True)
subject = serializers.CharField(source='subject.subject', read_only=True)
condition = serializers.CharField(source='condition.condition', read_only=True)
major = serializers.CharField(source='major.major', read_only=True)
state = serializers.CharField(source='state.state', read_only=True)
school = serializers.CharField(source='school.school', read_only=True)
location = serializers.CharField(source='location.location', read_only=True)
class Meta:
model = Product
fields = '__all__'
class SubjectSerializer(serializers.ModelSerializer):
model = Subject
fields = '__all__'
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('url', 'id', 'name')
class StateSerializer(serializers.ModelSerializer):
# state_count = serializers.SerializerMethodField()
class Meta:
model = State
fields = ['id', 'url', 'state']
# def get_state_count(self, obj):
# if State.objects.count()
# return obj.children().count()
# return 0
class ConditionSerializer(serializers.ModelSerializer):
class Meta:
model = Condition
fields = '__all__'
class MajorSerializer(serializers.ModelSerializer):
class Meta:
model = Major
fields = '__all__'
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = Location
fields = '__all__'
class FaqSerializer(serializers.ModelSerializer):
class Meta:
model = Faq
fields = '__all__'
views
from django.shortcuts import render
from rest_framework import viewsets, status
from rest_framework.decorators import api_view
from .models import Product, State, Category, Subject
from django.contrib.auth.models import User
from .serializer import *
from rest_framework.permissions import IsAuthenticated,AllowAny
from rest_framework.authentication import TokenAuthentication
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
from rest_framework.response import Response
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.pagination import LimitOffsetPagination
class ProductViewPagination(LimitOffsetPagination):
default_limit = 8
max_limit = 12
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
product_count = Product.objects.count()
authentication_classes = (TokenAuthentication,)
permission_calsses = (IsAuthenticated,)
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
search_fields = ('=title','=category__name','=user__id','=subject__subject', '=major__major', '=condition__condition', '=location__location')
pagination_class = ProductViewPagination
# def delete(self,request,*args,**kwargs):
# response = {'message':'product cannot be updated like this'}
# return Response(response, status = statu.HTTP_400_BAD_REQUEST)
# def create(self,request,*args,**kwargs):
# response = {'message':'product cannot be created like this'}
# return Response(response, status = status.HTTP_400_BAD_REQUEST)
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
permission_calsses = (IsAuthenticated,)
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
search_fields = ('=name', 'id')
class SubjectViewSet(viewsets.ModelViewSet):
queryset = Subject.objects.all()
serializer_class = SubjectSerializer
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
search_fields = ('=subject',)
class ConditionViewSet(viewsets.ModelViewSet):
queryset = Condition.objects.all()
serializer_class = ConditionSerializer
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
search_fields = ('=condition',)
class MajorViewSet(viewsets.ModelViewSet):
queryset = Major.objects.all()
serializer_class = MajorSerializer
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
search_fields = ('=major',)
class LocationViewSet(viewsets.ModelViewSet):
queryset = Location.objects.all()
serializer_class = LocationSerializer
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
search_fields = ('=location',)
# class StateCountViewSet(viewsets.ModelViewSet):
# queryset = State.objects.all()
# serializer_class = StateSerializer
# permission_calsses = (IsAuthenticated,)
# def get(self, request, format=None):
# state_count = State.objects.count()
# content = {'state_count' : state_count}
# return Response(content)
class StateViewSet(viewsets.ModelViewSet):
queryset = State.objects.all()
serializer_class = StateSerializer
permission_calsses = (IsAuthenticated,)
class FaqViewSet(viewsets.ModelViewSet):
queryset = Faq.objects.all()
serializer_class = FaqSerializer
permission_calsses = (AllowAny,)
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (AllowAny, )
# #api_view(['POST',])
# def registration_view(request):
# if request.method == 'POST':
# serializer = RegristrationSerializer(data=request.data)
# data = {}
# if serializer.is_valid():
# user = serialzer.save()
# data['response'] = "successfully registered a new userrrR"
# data['username'] = user.username
# else:
# data = serializer.errors
# return user
urls.py
from django.conf.urls import url, include
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets
from django.urls import path
from restapi.views import *
# class UserSerializer(serializers.HyperlinkedModelSerializer):
# class Meta:
# model = User
# fields = ['id', 'url', 'username', 'email', 'is_staff']
# # ViewSets define the view behavior.
# class UserViewSet(viewsets.ModelViewSet):
# queryset = User.objects.all()
# serializer_class = UserSerializer
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register('users', UserViewSet)
router.register('product', ProductViewSet)
router.register('category', CategoryViewSet)
router.register('state', StateViewSet)
#router.register('stateCount', StateCountViewSet)
router.register('subject', SubjectViewSet)
router.register('major', MajorViewSet)
router.register('condition', ConditionViewSet)
router.register('location', LocationViewSet)
router.register('faq', FaqViewSet)
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
#path('state/count/:state_id', StateCountViewSet, name='states-count')
]
admin.py
from django.contrib import admin
from .models import *
admin.site.register(Product)
admin.site.register(Category)
admin.site.register(Subject)
admin.site.register(State)
admin.site.register(Major)
admin.site.register(Condition)
admin.site.register(Location)
admin.site.register(Faq)
model.py
from django.db import models
from django.contrib.auth.models import User
# class User(models.Model):
# id_user = models.DecimalField(max_digits=10, decimal_places=2, null=True)
# def __str__(self):
# return self.id_user
class Faq(models.Model):
question = models.CharField(max_length = 400, null = True,)
answer = models.CharField(max_length = 900, null = True,)
def __str__(self):
return self.question
class Category(models.Model):
name = models.CharField(max_length = 200, null = True,)
def __str__(self):
return self.name
class State(models.Model):
STATE_CHOICES = [('Ordered', 'Ordered'), ('Pending', 'Pending'),
('Placed', 'Placed')
]
state = models.CharField(max_length = 200, null = True,
choices = STATE_CHOICES)
def __str__(self):
return self.state
class Subject(models.Model):
SUBJECT_CHOICES=[('Mathematics','Mathematics'),('Algoritmes','Algoritmes'),('Analyses','Analyses'),('Informatica','Informatica'),]
subject=models.CharField(max_length=200,null=True,choices=SUBJECT_CHOICES)
def __str__(self):return self.subject
class Major(models.Model):
MAJOR_CHOICES = (
('IT','IT'),
('Marketing','Marketing'),
('DIFF','DIFF'),
)
major = models.CharField(max_length=200,choices=MAJOR_CHOICES, null=True)
def __str__(self):return self.major
class Condition(models.Model):
CONDITION_CHOICES = [
('New','New'),
('Used','Used'),
]
condition = models.CharField(max_length=200,choices=CONDITION_CHOICES, null=True)
def __str__(self):return self.condition
class Location(models.Model):
LOCATION_CHOICES = [
('Brussel','Brussel'),
('Leuven','Leuven'),
('Gent','Gent'),
('Antwerpen','Antwerpen'),
]
location = models.CharField(max_length=200,choices=LOCATION_CHOICES, null=True)
def __str__(self):return self.location
class Product(models.Model):
user = models.ForeignKey(User,null=True, on_delete=models.SET_NULL)
state = models.ForeignKey(State, null=True, on_delete=models.SET_NULL)
category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)
subject = models.ForeignKey(Subject, null=True, on_delete=models.SET_NULL)
major = models.ForeignKey(Major, null=True, on_delete=models.SET_NULL)
condition = models.ForeignKey(Condition, null=True, on_delete=models.SET_NULL)
location = models.ForeignKey(Location, null=True, on_delete=models.SET_NULL)
title = models.CharField(max_length=200)
description = models.TextField(max_length=800, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2, null=True)
#image = models.ImageField(upload_to='post_image', blank=True, width_field=None, height_field=None, max_length=100,)
date_created = models.DateTimeField(auto_now_add=True, null=True)
class Meta:
unique_together = (('user','title'),)
index_together = (('user','title'),)
SCHOOL_CHOICES = (
('Erasmushogeschool | EHB',(
('Campus Kaai', 'Campus Kaai'),
('Campus Bloemberg', 'Campus Bloemberg'),
)),
('Vrije Universiteit Brussel | VUB',(
('Campus Jette', 'Campus Jette'),
('Campus Schaarbeek', 'Campus Schaarbeek'),
)),
('Katholieke universiteit leuven | KUL',(
('KUL Gent', 'KUL Gent'),
('Campus Antwerpen', 'Campus Antwerpen'),
)),
)
school = models.CharField(max_length=50, choices=SCHOOL_CHOICES, null=True)
# MAJOR_CHOICES = (
# ('IT','IT'),
# ('Marketing','Marketing'),
# ('DIFF','DIFF'),
# )
# major = models.CharField(max_length=200,choices=MAJOR_CHOICES, null=True)
# SUBJECT_CHOICES = [
# ('Mathematics','Mathematics'),
# ('Algoritmes','Algoritmes'),
# ('Analyses','Analyses'),
# ]
# subject = models.CharField(max_length=200,choices=SUBJECT_CHOICES, null=True)
# CONDITION_CHOICES = [
# ('New','New'),
# ('Used','Used'),
# ]
# condition = models.CharField(max_length=200,choices=CONDITION_CHOICES, null=True)
# LOCATION_CHOICES = [
# ('Brussel','Brussel'),
# ('Leuven','Leuven'),
# ('Gent','Gent'),
# ('Antwerpen','Antwerpen'),
# ]
# location = models.CharField(max_length=200,choices=LOCATION_CHOICES, null=True)
def __str__(self):
return self.title

Related

Filter current user products using queryset in DRF returns []

I am trying to filter list of products linked with a user. I want to display only current users product instead of listing all.
I tried this
class ProductCreateList(generics.ListCreateAPIView):
serializer_class = ProductSerializer
def get_queryset(self):
user = self.request.user
return Product.objects.filter(user=user.id)
serializers.py
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['id', 'user', 'name', 'imgUrl', 'selling_price', 'actual_price', 'quantity', 'get_profit']
models.py
class Product(models.Model):
user = models.ForeignKey('accounts.Account', on_delete=models.CASCADE, default=1)
name = models.CharField(max_length=100, null=True, blank=True)
imgUrl = models.TextField(default='')
selling_price = models.FloatField(null=True, blank=True)
actual_price = models.FloatField(null=True, blank=True)
quantity = models.IntegerField()
I got [] object when I tried to execute the endpoint. What's my mistake here?
There are a few mistakes, mainly in your view. I have done the following:
models.py
from django.db import models
from django.contrib.auth import get_user_model
class Product(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, default=1)
name = models.CharField(max_length=100, null=True, blank=True)
imgUrl = models.TextField(default='')
selling_price = models.FloatField(null=True, blank=True)
actual_price = models.FloatField(null=True, blank=True)
quantity = models.IntegerField()
class Meta:
db_table = 'product'
serializers.py: Remove 'get_profit' field or implement a serializermethodfield
from rest_framework import serializers
from core.models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['id', 'user', 'name', 'imgUrl', 'selling_price', 'actual_price', 'quantity']
views.py: To filter by user, guarantee that the user is Authenticated and has auth permission by using authentication_classes and permission_classes. Use the filter_queryset hook, to filter your queryset by user.
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework import generics
from core.api.serializers import ProductSerializer
from core.models import Product
class ProductCreateList(generics.ListCreateAPIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
serializer_class = ProductSerializer
queryset = Product.objects.all()
def filter_queryset(self, queryset):
queryset = queryset.filter(user=self.request.user)
return super().filter_queryset(queryset)

Django_filter on an apiview

I have been trying to use the Django_filter on an APIView, but it just does not work. I am trying to implement a filter search, on some fields on a model.
below is how the model is set up
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
name = models.CharField(max_length=250)
picture = models.TextField(null=True, blank=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(max_length=255, unique=True, blank=True)
class Skill(models.Model):
name = models.CharField(max_length=60)
subcategory = models.CharField(max_length=60, blank=True, null=True)
created_on = models.DateTimeField(auto_now=True)
updated_on = models.DateTimeField(auto_now_add=True)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.DO_NOTHING)
the views.py set up is also as shown below
from django_filters import rest_framework as filters
class UserFilter(filters.FilterSet):
email = filters.CharFilter(lookup_expr='icontains')
name = filters.CharFilter(lookup_expr='icontains')
profiles__skills = filters.CharFilter(lookup_expr='icontains')
class Meta:
model = User
fields = ('email', 'name', 'profiles__skills')
class ListUsersView(APIView, MyPaginationMixin):
'''
Gets all the users in the database
'''
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [AllowAny]
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
filterset_class = UserFilter
def get(self, request):
page = self.paginate_queryset(self.queryset)
if page is not None:
serializer_context = {"request": request}
serializer = self.serializer_class(page, context=serializer_context, many=True)
return self.get_paginated_response(serializer.data)
and finally my serializer.py
class UserSerializer(serializers.ModelSerializer):
slug = serializers.SlugField(read_only=True)
class Meta:
model = User
fields = ('email', 'name', 'slug', 'picture')
read_only_fields = ('email', 'name', 'slug',)
my urls.py
path('users/', qv.ListUsersView.as_view(), name='list-users'),
this is how my result looks like
please, how can I get the Django filter to work on the APIView
It seems you are trying to get the similar or exact behavior of DRF ListAPIView by using APIView. I would suggest using ListAPIView over APIView in your case.
from rest_framework import generics
from django_filters import rest_framework as filters
class ListUsersView(generics.ListAPIView):
'''
Gets all the users in the database
'''
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [AllowAny]
filterset_class = UserFilter
filter_backends = (filters.backends.DjangoFilterBackend,)
To add filtering capability in APIView,
class MyAPIViewKlass(APIView):
filter_backends = (filters.DjangoFilterBackend,)
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
def get(self, request, *args, **kwargs):
base_qs = MyModel.objects.all()
filtered_qs = self.filter_queryset(base_qs)
serializer = MySerializer(filtered_qs, many=True)
return Response(serializer.data)

Why my slug related field shows users object(1) instead of suggested field name in Django?

I wrote an app named as credentials.
models, serializers and views are :
models.py :
from django.db import models
class Users(models.Model):
username = models.CharField(max_length=20, blank=False)
inserted_timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('inserted_timestamp',)
class UsersDetails(models.Model):
user = models.ForeignKey(
Users,
related_name='id_user_details',
on_delete=models.DO_NOTHING,
)
user_title = models.CharField(max_length=30, blank=True)
user_first_name = models.CharField(max_length=25, blank=True)
user_last_name = models.CharField(max_length=40, blank=True)
user_birthdate = models.DateField(blank=False)
inserted_timestamp = models.DateTimeField(auto_now_add=True)
details_creator = models.ForeignKey(
Users,
related_name='dtlcreator_user_details',
on_delete=models.DO_NOTHING,
# default=1
)
class Meta:
ordering = ('user_id',)
class UsersPasswords(models.Model):
user = models.ForeignKey(
Users,
related_name='id_user_password',
on_delete=models.DO_NOTHING)
salt = models.CharField(max_length=200, blank=True)
pwdhash = models.CharField(max_length=200, blank=True)
inserted_timestamp = models.DateTimeField(auto_now_add=True)
pwd_creator = models.ForeignKey(
Users,
related_name='pwdcreator_user_details',
on_delete=models.DO_NOTHING)
class Meta:
ordering = ('user_id',)
Here is serializers.py :
from rest_framework import serializers
from credentials.models import Users
from credentials.models import UsersDetails
from credentials.models import UsersPasswords
class UsersSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Users
fields = (
'url',
'pk',
'username',
'inserted_timestamp',
)
class UsersDetailsSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.SlugRelatedField(
queryset=Users.objects.all(),
slug_field='username',
)
details_creator = serializers.SlugRelatedField(
queryset=Users.objects.all(),
slug_field='username',
)
class Meta:
model = UsersDetails
fields = (
'url',
'pk',
'user',
'user_title',
'user_first_name',
'user_last_name',
'user_birthdate',
'inserted_timestamp',
'details_creator'
)
class UsersPasswordsSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.SlugRelatedField(
queryset=Users.objects.all(),
slug_field='username'
)
pwd_creator = serializers.SlugRelatedField(
queryset=Users.objects.all(),
slug_field='username'
)
class Meta:
model = UsersPasswords
fields = (
'pk',
'user',
'salt',
'pwdhash',
'inserted_timestamp',
'pwd_creator'
)
class UsersDetailsPasswordsSerializer(serializers.HyperlinkedModelSerializer):
details = UsersDetailsSerializer(many=True, read_only=True)
passwords = UsersPasswordsSerializer(many=True, read_only=True)
class Meta:
model = Users
fields = (
'url',
'pk',
'username',
'inserted_timestamp',
'details',
'passwords',
)
views.py :
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.reverse import reverse
from credentials.models import Users, UsersDetails, UsersPasswords
from credentials.serializers import UsersSerializer, UsersDetailsSerializer, UsersPasswordsSerializer
class UserList(generics.ListCreateAPIView):
queryset = Users.objects.all()
serializer_class = UsersSerializer
name = 'users-list'
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Users.objects.all()
serializer_class = UsersSerializer
name = 'users-detail'
class UserDetailsList(generics.ListCreateAPIView):
queryset = UsersDetails.objects.all()
serializer_class = UsersDetailsSerializer
name = 'usersdetails-list'
class UserDetailsDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = UsersDetails.objects.all()
serializer_class = UsersDetailsSerializer
name = 'usersdetails-detail'
class UserPasswordsList(generics.ListCreateAPIView):
queryset = UsersPasswords.objects.all()
serializer_class = UsersPasswordsSerializer
name = 'userpasswords-list'
class UserPasswordsDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = UsersPasswords.objects.all()
serializer_class = UsersPasswordsSerializer
name = 'userpasswords-detail'
class ApiRoot(generics.GenericAPIView):
name = 'api-root'
def get(self, request, *args, **kwargs):
return Response({
'user-list': reverse(UserList.name, request=request),
'user-details': reverse(UserDetailsList.name, request=request),
'user-passwords': reverse(UserPasswordsList.name, request=request),
})
When I intended to add new user details I expect to see username field values but I see users object (1) instread of username, like below picture:
What's your idea?
Set __str__ method on Users:
class Users(models.Model):
...
def __str__(self):
return self.username

Django Rest Framework: Serialize multiple images to one post in

I am trying to be able to serialize and upload multiple images to associate with each post.
This is my models.py
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save
from .utils import unique_slug_generator
class Painting(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default="", on_delete=models.CASCADE)
title = models.CharField(blank=False, null=False, default="", max_length=255)
slug = models.SlugField(blank=True, null=True)
style = models.CharField(blank=True, null=True, default="", max_length=255) #need to figure out why there is problem when this is False
description = models.TextField(blank=True, null=True, default="")
size = models.CharField(blank=True, null=True, default="", max_length=255)
artist = models.CharField(blank=True, null=True, default="", max_length=255)
price = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=20)
available = models.BooleanField(default=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __str__(self):
return self.title
class Meta:
ordering = ["-timestamp", "-updated"]
class PaintingPhotos(models.Model):
title = models.ForeignKey(Painting, default="", on_delete=models.CASCADE)
image = models.ImageField(upload_to='uploaded_paintings')
def pre_save_painting_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(pre_save_painting_receiver, sender=Painting)
my serializers.py
from django.contrib.auth import get_user_model, authenticate, login, logout
from django.db.models import Q
from django.urls import reverse
from django.utils import timezone
from rest_framework import serializers
from .models import Painting, PaintingPhotos
User = get_user_model()
class UserPublicSerializer(serializers.ModelSerializer):
username = serializers.CharField(required=False, allow_blank=True, read_only=True)
class Meta:
model = User
fields = [
'username',
'first_name',
'last_name',
]
# # add PaintingImagesSerializer with the images model here
class PaintingPhotosSerializer(serializers.ModelSerializer):
class Meta:
model = PaintingPhotos
fields =[
'image'
]
#becareful here, if anyone submits a POST with an empty title, it will result in the empty slug, (which will mess up the url lookup since the title is the slug in this case)
#make title a required field in the actual interface, also remember to don't submit s POST with an empty title from the Django restframework directly
class PaintingSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='paintings-api:detail',
read_only=True,
lookup_field='slug'
)
user = UserPublicSerializer(read_only=True)
owner = serializers.SerializerMethodField(read_only=True)
image = PaintingPhotosSerializer(many=True, read_only=False)
class Meta:
model = Painting
fields = [
'url',
'user',
'title',
'style',
'description',
'size',
'artist',
'price',
'available',
'updated',
'timestamp',
'owner',
'slug',
'image',
]
def get_owner(self, obj):
request = self.context['request']
if request.user.is_authenticated:
if obj.user == request.user:
return True
return False
my views.py
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework import generics, permissions, pagination, status
from .models import Painting
from .permissions import IsOwnerOrReadOnly
from .serializers import PaintingSerializer
class PaintingPageNumberPagination(pagination.PageNumberPagination):
page_size = 5
page_size_query_param = 'size'
max_page_size = 20
def get_paginated_response(self, data):
author = False
user = self.request.user
if user.is_authenticated:
author = True
context = {
'next': self.get_next_link(),
'previous': self.get_previous_link(),
'count': self.page.paginator.count,
'author': author,
'results': data,
}
return Response(context)
class PaintingDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Painting.objects.all()
serializer_class = PaintingSerializer
lookup_field = 'slug'
permission_classes = [IsOwnerOrReadOnly]
class PaintingListCreateAPIView(generics.ListCreateAPIView):
queryset = Painting.objects.all()
serializer_class = PaintingSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
pagination_class = PaintingPageNumberPagination
def perform_create(self, serializer):
serializer.save(user=self.request.user)
I am getting this error:
AttributeError: Got AttributeError when attempting to get a value for field image on serializer PaintingSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Painting instance.
Original exception text was: 'Painting' object has no attribute 'image'.
I am also not sure if I should create another app just to handle all the images.
Thanks so much in advance!
Your code looks similar enough to the docs here: https://www.django-rest-framework.org/api-guide/relations/#nested-relationships I can't see what exactly is wrong, but it could be that you haven't created a PaintingPhotos object so there is no model to serialize it. I mentioned in a comment that you can create this through the Django admin.
Hey guys I ended up finding the answer. This stackoverflow answer explains it really well: Multiple images per Model
where I messed up was not adding the related_name argument to my photo in my PaintingPhotos model.

expand search and return all objects Django REST Framework

Currently in my ModelViewSet I'm returning all contacts for today, additionally I'm checking if the query_params on the request for searching/filtering is available and not empty, In that case I'm not adding "today" to the queryset so that will perform search on the entire queryset.
Problem is that I need to extend search so the user can see other users contacts, but only when he search for them, default view should not be changing if you are not searching, so how can I extend my current filter and return all objects in search.
My current view:
from rest_framework import viewsets, permissions, filters
from cms.restapi.pagination import StandardResultsOffsetPagination
from cms_sales.models import LeadContact
from cms_sales.restapi.permissions.lead_contact_permissions import LeadContactPermissions
from cms_sales.restapi.serializers.lead_contact_serializer import LeadContactSerializer
class LeadContactViewSet(viewsets.ModelViewSet):
def get_queryset(self):
queryset = LeadContact.objects.none()
user = self.request.user
if user.has_perm('cms_sales.can_view_full_lead_contact_list'):
queryset = LeadContact.objects.all()
elif user.has_perm('cms_sales.can_view_lead_contact'):
queryset = LeadContact.objects.filter(account_handler=user)
filter_date = self.request.query_params.get('filter_date', None)
search_params = self.request.query_params.get('search', None)
if filter_date is not None and (search_params is None or len(search_params) == 0):
queryset = queryset.filter(next_action_date=filter_date)
return queryset
serializer_class = LeadContactSerializer
filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
filter_fields = ('account_handler',)
ordering_fields = (
'first_name', 'last_name', 'account_handler__first_name', 'account_handler__last_name',
'sub_organization_name', 'organization_name', 'next_action_date', 'serial_number',
'status_text')
search_fields = (
'first_name', 'last_name', 'account_handler__first_name', 'account_handler__last_name',
'sub_organization_name', 'organization_name', 'next_action_date', 'serial_number',
'status_text')
pagination_class = StandardResultsOffsetPagination
permission_classes = [permissions.IsAuthenticated, LeadContactPermissions]
Current Serializer:
from django.conf import settings
from django.contrib.auth.models import User
from rest_framework import serializers
from cms_sales.models import LeadContact
class AccountHandlerSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name')
class LeadContactSerializer(serializers.ModelSerializer):
account_handler = AccountHandlerSerializer()
next_action_date = serializers.DateTimeField(format=settings.CUSTOM_DATE_FORMAT_NO_TIME)
absolute_url = serializers.URLField(source='get_absolute_url')
class Meta:
model = LeadContact
fields = (
'pk', 'organization_name', 'sub_organization_name', 'serial_number', 'account_handler', 'status_text',
'first_name', 'last_name', 'next_action_date', 'absolute_url', 'status_display_class'
)
depth = 1
Current Model:
class LeadContact(models.Model):
organization_name = models.CharField(max_length=200, blank=False, null=True)
sub_organization_name = models.CharField(max_length=200, blank=False, null=True)
serial_number = models.CharField(max_length=30, db_index=True, blank=True, null=True)
account_handler = models.ForeignKey(User, blank=True, null=True, related_name='handling_leads', on_delete=models.SET_NULL)
next_action_date = models.DateField(null=True, verbose_name="Next action on lead")
status_text = models.CharField(max_length=20, default='', blank=True)
first_name = models.CharField(_('first name'), max_length=30)
last_name = models.CharField(_('last name'), max_length=30)
move the code to check permissions below the code where you check for search param so that you are applying the user filter after checking for search_params
def get_queryset(self):
queryset = LeadContact.objects.all()
if (not user.has_perm('cms_sales.can_view_full_lead_contact_list') and
not user.has_parm('cms_sales.can_view_lead_contact')):
return queryset.none()
user = self.request.user
filter_date = self.request.query_params.get('filter_date', None)
search_params = self.request.query_params.get('search', None)
if filter_date is not None and (search_params is None or len(search_params) == 0):
queryset = queryset.filter(next_action_date=filter_date)
if user.has_perm('cms_sales.can_view_lead_contact') and not search_params:
queryset = queryset.filter(account_handler=user)
return queryset