Django Attribute Error when using serializer - python

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)

Related

DRF + Djongo: How to access and work with ID from legacy database?

I set up a Django REST Framework (DRF) in combination with djongo, since I'm having a legacy database in MongoDB/Mongo express. Everything runs through a docker container, but I don't think that this is the issue. My model looks like this:
from django.db import models
## Event
class Event(models.Model):
ID = models.AutoField(primary_key=True)
date = models.DateField(default=None)
name = models.CharField(default=None, max_length=500)
locality = models.CharField(default=None, max_length=500)
class Meta:
ordering = ['ID']
db_table = 'event'
Next, my serializer is as follows:
from rest_framework import serializers
from .models import Event
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
fields= "__all__"
And the view looks like this:
from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .serializers import *
from .models import *
## Events
#api_view(['GET', 'POST'])
def event_list(request):
if request.method == 'GET':
events = Event.objects.all().order_by('ID')
event_serializer = EventSerializer(events, many=True)
return Response(event_serializer.data)
elif request.method == 'POST':
event_serializer = EventSerializer(data=request.data)
if event_serializer.is_valid():
event_serializer.save()
return Response(event_serializer.data, status=status.HTTP_201_CREATED)
return Response(event_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
As soon as I'm trying to post with
import requests
endpoint = "http://localhost:8080/event/"
get_response = requests.post(endpoint, {"date":"2022-06-01", "name":"Max Musterfrau", "locality":"North America"} )
I'm getting back the error message
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'ObjectId'
Following the documentation and other StackOverflow questions, in my model ID = models.AutoField(primary_key=True) should create the index ID as the primary key and auto-increments it. But at the same time, MongoDB creates its own _id and the actual ID from my legacy database doesn't auto-increment. I've tried both suggested solutions from here, but unfortunately it didn't change a thing. Therefore, my question is: How can I auto-increment the ID from my legacy database when POSTing an object? How do I create it automatically?
We need to create Separate serializer filed for _id = ObjectIdField like below
from bson import ObjectID
from bson.errors import InvalidID
class ObjectIdField(serializers.Field):
""" Serializer field for Djongo ObjectID fields """
def to_internal_value(self, data):
# Serialized value -> Database value
try:
return ObjectId(str(data)) # Get the ID, then build an ObjectID instance using it
except InvalidId:
raise serializers.ValidationError(
'`{}` is not a valid ObjectID'.format(data)
def to_representation(self, value):
# Database value -> Serialized value
if not ObjectId.is_valid(value): # User submitted ID's might not be properly structured
raise InvalidId
return smart_text(value)
class EventSerializer(ModelSerializer):
_id = ObjectIdField(read_only=True)
class Meta:
model = Event
fields = '__all__'

Object has no attribute get in serializer

I created a serializer and an API endpoint so I can retrieve some data from a Django DB in my React app but getting this error message:
AttributeError: 'ProgrammingChallengesView' object has no attribute 'get'
Here is my models.py:
#creating programming challenges
class ProgrammingChallenges(models.Model):
challenge_id = models.AutoField(primary_key=True)
challenge_name = models.CharField(max_length=200)
challenge_description = models.TextField()
challenge_expectations = models.TextField()
my serializer:
from accounts.models import ProgrammingChallenges
...
class ProgrammingChallengesView(serializers.ModelSerializer):
class Meta:
model = ProgrammingChallenges
fields = '__all__'
and my urls.py:
path('api/programming_challenges/', ProgrammingChallengesView, name='programming_challenges'),
Thanks to the comments; I clearly didn't understand that a serializer only transforms my data to make it available through an API. I still had to create a view for my API's endpoint.
I opted to create a ReadOnlyModelView because I only want to GET data from this endpoint.
Here is what I wrote in my views:
class ProgrammingChallengesView(ReadOnlyModelViewSet):
serializer_class = ProgrammingChallengesSerializer
queryset = ProgrammingChallenges.objects.all()
#action(detail=False)
def get_list(self, request):
pass
and in my urls.py:
path('api/programming_challenges/', ProgrammingChallengesView.as_view({'get':'list'}), name='programming_challenges'),
I think you shouldn't hurry read the docs again. You are trying to use serializers as views.
Models - are representation of db tables as class.
Serializer serializes the data to json.
View accepts the reqeust from client and returns a Response.
Code shoudld be:
models.py
class ProgrammingChallenge(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
expectations = models.TextField()
Your model name should be ProgrammingChallenge(singular) not ProgrammingChallenges(plural).
You should't add prefix challenge before all field names. Because we already know that the fields are in a Model called ProgrammingChallenge. And it is easy to access them like ProgrammingChallenge.name than ProgrammingChallenge.challenge_name
You don't have to add field id manually. Django model automatically adds id field as primary_key
serializer.py
from accounts.models import ProgrammingChallenge
...
class ProgrammingChallengeSerializer(serializers.ModelSerializer):
class Meta:
model = ProgrammingChallenge
fields = '__all__'
No problem in serialize.
Now, main problem is you don't have any view. You definetly read docs. You can use APIView, generic views or viewset. In this example i'm going to use ViewSet that handles CRUD operations built in.
viewsets.py
from rest_framework.viewsets import ModelViewSet
from .models import ProgrammingChallenge
from .serializers import ProgrammingChallengSerializer
class ProgrammingChallengViewSet(ModelViewSet):
queryset = ProgrammingChallenge.objects.all()
serializer_class = ProgrammingChallengeSerializer
urls.py
from rest_framework.routers import SimpleRouter
from .viewsets import ProgrammingChallenge
router = SimpleRouter()
router.register('challengr', ProgrammingChallengeViewSet)
urlpatterns = router.urls
Another advantage of using viewset, it also generate all endpoint for it's CRUD methods automatically via routes.
It should help you to start your first project.
AGAIN, READ THE DOCS!

Django use Different Serializer based on parameter

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

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

AttributeError while using Django Rest Framework with serializers

I am following a tutorial located here that uses Django Rest Framework, and I keep getting a weird error about a field.
I have the following model in my models.py
from django.db import models
class Task(models.Model):
completed = models.BooleanField(default=False)
title = models.CharField(max_length=100)
description = models.TextField()
Then my serializer in serializers.py
from rest_framework import serializers
from task.models import Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ('title', 'description', 'completed')
and my views.py as follows:
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from task.models import Task
from api.serializers import TaskSerializer
#api_view(['GET', 'POST'])
def task_list(request):
"""
List all tasks, or create a new task
"""
if request.method == 'GET':
tasks = Task.objects.all()
serializer = TaskSerializer(tasks)
return Response(serializer.data)
elif request.method == 'POST':
serializer = TaskSerializer(data=request.DATA)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(
serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
and my urls.py has this line:
url(r'^tasks/$', 'task_list', name='task_list'),
When I try accessing curl http://localhost:9000/api/tasks/, I keep getting the following error and I'm not sure what to make of it:
AttributeError at /api/tasks/
Got AttributeError when attempting to get a value for field `title` on serializer `TaskSerializer`.
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 'title'.
What I'm I missing?
Simple specify many=True when creating a serializer from queryset, TaskSerializer(tasks) will work only with one instance of Task:
tasks = Task.objects.all()
serializer = TaskSerializer(tasks, many=True)
The problem here is that you are trying to convert a Queryset(list) of entries into a single entry. The solution is something along these lines.
from rest_framework import serializers
class TaskListSerializer(serializers.ListSerializer):
child = TaskSerializer()
allow_null = True
many = True
Then
if request.method == 'GET':
tasks = Task.objects.all()
serializer = TaskListSerializer(tasks)
return Response(serializer.data)

Categories