Django use Different Serializer based on parameter - python

I have a APIView that provides my model instances. I want to use different serializers based on url parameters, beacause I want to serve different fields based on parameter. I didn't want to use if else check for all situations, so I used a function that provide serializer from serializer objects dict based on type key. Is there a good solution? Does anyone have a better suggestion?
Also what are you thinking about use different endpoints instead of this method.
Here is the code:
urls.py
from django.urls import path
from .views import MySerializerTestView
urlpatterns = [
path('<slug:type>', MySerializerTestView.as_view()),
]
models.py
from django.db import models
class MyModel(models.Model):
field_first = models.CharField(max_length=10)
field_second = models.CharField(max_length=10)
field_third = models.CharField(max_length=10)
views.py
from .models import MyModel
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import MyFirstSerializer,MySecondSerializer,MyThirdSerializer
class MySerializerTestView(APIView):
def get(self, request, **kwargs):
my_data = MyModel.objects.all()
serializer = self.get_serializer(self.kwargs['type'],my_data)
return Response(serializer.data)
def get_serializer(self,type,data):
my_serializers = {
'first':MyFirstSerializer(data,many=True),
'second':MySecondSerializer(data,many=True),
'third':MyThirdSerializer(data,many=True),
}
return my_serializers[type]
serializers.py
from .models import MyModel
from rest_framework import serializers
class MyFirstSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ['field_first']
class MySecondSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ['field_second']
class MyThirdSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ['field_third']

You can send a parameter or select the serializer based on the action that is taken.
In your "view.py" file you can use the "get_serializer_class (self)" method to do it.
def get_serializer_class(self):
if 'parameter' in self.request.query_params:
return ParameterSerializer
if self.action == "list" or self.action == 'retrieve':
return ListSerializer
else:
return CreateSerializer

Related

Django Attribute Error when using serializer

I would like to fetch the entire table. My model and serializer seems to be correct but I am getting the below error
Got AttributeError when attempting to get a value for field symbol on serializer CompanySerializer.
The serializer field might be named incorrectly and not match any attribute or key on the QuerySet instance.
Original exception text was: 'QuerySet' object has no attribute 'symbol'.
Below is my Model
models.py
from django.db import models
class Companies(models.Model):
symbol = models.CharField(max_length=100)
name = models.CharField(max_length=255)
isin = models.CharField(max_length=255)
serializers.py
from rest_framework import serializers
from .models import Companies
class CompanySerializer(serializers.ModelSerializer):
class Meta:
fields = ['symbol', 'name', 'isin',]
# fields = '__all__'
model = Companies
Below is my view
views.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Companies
from .serializers import CompanySerializer
from django.core.serializers import json
class companiesView(APIView):
def get(self, request):
companies = Companies.objects.filter(id=1)
serializer = CompanySerializer(companies)
# json_serializer = json.Serializer()
# json_serialized = json_serializer.serialize(companies)
response = Response()
response.data = {
'named' : serializer.data,
}
return response
I am not sure what is causing this issue. Thanks in Advance.
companies is a queryset, so what you have is a list of companies. If you want your serializer to work with a list of objects, just add many=True:
companies = Companies.objects.filter(id=1)
serializer = CompanySerializer(companies, many=True)
# ^^^ Add this
Another way is to just get the company with id 1 using get instead of filter. In this case you don't have to add many=True since the serializer is working on a single object:
companies = Companies.objects.get(id=1)
# ^^^ Use get instead of filter
serializer = CompanySerializer(companies)

validate method not called django rest framework

I am trying to test validate method on modelSerializer but it is NOT CALLED.
Why is not working ? Have i been missed something ? the same scenario works at different project
at urls
urlpatterns = [ path('api/allposts/', allposts, name='allposts') ]
at views:
from .serializer import PostSerializer
from rest_framework.renderers import JSONRenderer
from .models import Post
from django.http import JsonResponse
import json
def allposts(request):
qs = Post.objects.all()[:3]
ser = PostSerializer(qs, many=True)
data = JSONRenderer().render(ser.data)
return JsonResponse(json.loads(data), safe=False)
at models
class Post(models.Model):
title = models.CharField(max_length=100)
url = models.URLField()
poster = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created']
def __str__(self):
return self.title
at serializer
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['title', 'poster', 'url']
def validate(self, data):
if 'facebook' in data.get('url'):
raise serializers.ValidationError('you can not add facebook')
return data
serializer's validate method is called when you call serializer.is_valid(). Since you are serializing db instances you are not required to call is_valid(), hence validate() method is not called

Cannot get instance value in Django rest update view

I am using Django 3.0 djangorestframework==3.11.0. I have created a task update view and passing the pk to url. The problem is - Although I have set the serializer instance to the model object I want to update. The serializer instance is not showing up.
models.py
from django.db import models
# Create your models here.
class Task(models.Model):
title = models.CharField(max_length=200)
completed = models.BooleanField(default=False, blank=True, null=True)
def __str__(self):
return self.title
serializers.py
from rest_framework import serializers
from .models import Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.apiOverview, name='api-overview'),
path('task-list/', views.taskList, name='task-list'),
path('task-detail/<str:pk>/', views.taskDetail, name='task-detail'),
path('task-create/', views.taskCreate, name='task-create'),
path('task-update/<str:pk>/', views.taskUpdate, name='task-update'),
]
views.py
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Task
from .serializers import TaskSerializer
#api_view(['POST'])
def taskUpdate(request, pk):
task = Task.objects.get(id=pk)
serializer = TaskSerializer(instance=task, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
expected behavior on url http://localhost:8000/api/task-update/4/
actual behaviour on http://localhost:8000/api/task-update/4/
as you can see the content field is empty but I want the already associated json to be shown there with pk = 4.

query data from one model, filter from another

I would like to display values from one table, but filter these values based on a value from another table.
for example: I want to display values from data/models.py that are filtered by the customer_tag in the CustomUser table (accounts/models.py).
These are related tables, but I can't figure out the right syntax to filter this view.
Any ideas? Or is this not possible with my current schema..
data/views.py
from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, DeleteView, CreateView
from django.urls import reverse_lazy
from .models import Data
from django.contrib.auth.mixins import LoginRequiredMixin
from rest_framework import generics
from .models import Data
from accounts.models import CustomUser
from .serializers import DataSerializer
from .permissions import IsAuthorOrReadOnly
class DataListView(LoginRequiredMixin,ListView):
queryset = Data.objects.all()
context = {
"object_list": queryset
}
template_name = 'data_list.html'
login_url = 'login'
accounts/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
customer_Tag = models.CharField(max_length=50,)
isAdmin = models.BooleanField(default = False,)
notifications = models.BooleanField(default = True,)
deviceSerial= models.CharField(max_length=50,)
machineName= models.CharField(max_length=50,default="ESP1",)
machineDescription = models.CharField(max_length=200,)
class Customer(models.Model):
customerTag= models.CharField(max_length=50,)
customerName = models.CharField(max_length=50,)
mainContact = models.CharField(max_length=100,default='',)
Address = models.CharField(max_length=100,default='',)
city = models.CharField(max_length=100,default='',)
website = models.URLField(max_length=100,default='',)
phone = models.IntegerField(default=0,)
def __str__(self):
return self.customerName
data/models.py
from django.db import models
from django.conf import settings
from django.contrib.auth import get_user_model
class Data(models.Model):
author = models.ForeignKey(get_user_model(),on_delete=models.CASCADE,)
tempData= models.CharField(max_length=50,blank=True,)
humidData= models.CharField(max_length=50,blank=True,)
def __str__(self):
return str(self.author)
It's all in the docs: https://docs.djangoproject.com/en/2.1/topics/db/queries/#lookups-that-span-relationships
Fields of related models are queried using double underscores __ in a filter.
In your case you need to override get_queryset method of your DataListView class to return a filtered queryset:
class DataListView(LoginRequiredMixin,ListView):
...
def get_queryset(self):
return self.queryset.filter(author__customerTag=self.request.user.customerTag)
I think you are looking for the key__field argument of the filter query if I understood you correctly. So in your case it would be something like,
Data.objects.filter(author__customer_tag='tag-you-are-looking-for') # double underscores after author
Hope this answers your question!

AttributeError at /app/api/get

I got an error,
AttributeError at /app/api/get
Got AttributeError when attempting to get a value for field task_name on serializer TaskSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Color instance.
Original exception text was: 'Color' object has no attribute 'task_name'.
Now I wanna make a page that shows model's content in json format.
models.py is
from django.db import models
# Create your models here.
class Color(models.Model):
name = models.CharField(max_length=255)
background_color = models.CharField(max_length=255)
h1_color = models.CharField(max_length=255)
p_color = models.CharField(max_length=255)
def __str__(self):
return self.name
serializers.py is
from .models import Color
from rest_framework import serializers
class TaskSerializer(serializers.Serializer):
task_name = serializers.CharField(max_length=100)
status = serializers.SerializerMethodField('get_task_status')
def get_task_status(self, instance):
return instance.status.status
class Meta:
model = Color
fields = ('name',
'background_color',
'h1_color',
'p_color',
'task_name')
urls.py is
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'api/get',views.TaskGet.as_view(),name='task-get')
]
views.py is
from django.shortcuts import render
from .models import Color
from .forms import ColorForm
from .serializers import TaskSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
# Create your views here.
def index(request):
d = {
'colors': Color.objects.all(),
'form': ColorForm(),
}
return render(request, 'index.html', d)
class TaskGet(APIView):
def get(self, request, format=None):
obj = Color.objects.all()
serializers = TaskSerializer(obj, many=True)
return Response(serializers.data, status.HTTP_200_OK)
I wrote url(r'api/get',views.TaskGet.as_view(),name='task-get') in urls.py,so I really cannot understand why this error happens.I already run commands of migration of model. How can I fix this?
My ideal web page is like
You try get status by foreign key instance.status.status but in your model class Color i don't see any foreign keys or methods for it.
And for task_name did you want to see the model field name try to add source params
task_name = serializers.CharField(max_length=100, source='name')
# ^^^^^^^^^
are you sure you want serialize Task for model Color?
new edit
in your get_task_status the 'instanceis instance of serializer model, so if your modelColorhas no property or methodstatus` you will catch an error

Categories