I want to use Django REST framework to create an API to call different methods. I read the guide of [django-rest-framework][1] to work with this framework, but I still have some questions.
I have no model I get my data from an external database. I want to try first something simple:
Get all list of project
Get the data from one project
For that I create new app I include in the setting file and in my view.py I include that for the fist case
def connect_database():
db = MySQLdb.connect(host='...', port=, user='...', passwd='...', db='...')
try:
cursor = db.cursor()
cursor.execute('SELECT * FROM proj_cpus')
columns = [column[0] for column in cursor.description]
# all_rows = cursor.fetchall()
all_rows = []
for row in iter_row(cursor):
all_rows.append(dict(zip(columns, row)))
finally:
db.close()
return all_rows
def iter_row(cursor, size= 1000):
while True:
results = cursor.fetchmany(size)
if not results:
break
for item_result in results:
yield item_result
class cpuProjectsViewSet(viewsets.ViewSet):
serializer_class = serializers.cpuProjectsSerializer
def list(self, request):
all_rows = connect_database()
name_project = []
for item_row in all_rows:
name_project.append(item_row['project'])
name_project = list(sorted(set(name_project)))
serializer = serializers.cpuProjectsSerializer(instance=name_project, many=False)
return Response(serializer.data)
my serializers file I have this
class cpuProjectsSerializer(serializers.Serializer):
project = serializers.CharField(max_length=256)
def update(self, instance, validated_data):
instance.project = validated_data.get('project', instance.project)
return instance
Now when I execute this http://127.0.0.1:8000/hpcAPI
I obtain this error
Got AttributeError when attempting to get a value for field `project` on serializer `cpuProjectsSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `list` instance.
Original exception text was: 'list' object has no attribute 'project'.
I look for in google and I change this
serializers.cpuProjectsSerializer(instance=name_project, many=False) for
serializers.cpuProjectsListSerializer(instance=name_project, many=False)
but I obtain the same error!
any idea about that!
Thanks in adavances
From docs here.You don't have to have a model for create a Serializer class.You can define some serializers field then use them. You should not import CPUProjectsViewSet and also define it in below
from mysite.hpcAPI.serializers import CPUProjectsViewSet
class CPUProjectsViewSet(viewsets.ViewSet):
"""
return all project name
"""
all_rows = connect_database()
Related
Currently I'm trying to create an expected json to use in my test:
#pytest.mark.django_db(databases=['default'])
def test_retrieve_boards(api_client):
board = baker.make(Board)
objs = BoardSerializerRetrieve(board)
print(objs.data)
url = f'{boards_endpoint}{board.id}/'
response = api_client().get(url)
assert response.status_code == 200
But i'm receiving the following error:
AttributeError: Got AttributeError when attempting to get a value for field `cards_ids` on serializer `BoardSerializerRetrieve`.
E The serializer field might be named incorrectly and not match any attribute or key on the `Board` instance.
E Original exception text was: 'Board' object has no attribute 'cards_ids'
Currently cards_idsare added on my viewSet on get_queryset method:
def get_queryset(self):
#TODO: last update by.
#TODO: public collections.
"""Get the proper queryset for an action.
Returns:
A queryset object according to the request type.
"""
if "pk" in self.kwargs:
board_uuid = self.kwargs["pk"]
qs = (
self.queryset
.filter(id=board_uuid)
.annotate(cards_ids=ArrayAgg("card__card_key"))
)
return qs
return self.queryset
and this is my serializer:
class BoardSerializerRetrieve(serializers.ModelSerializer):
"""Serializer used when retrieve a board
When retrieve a board we need to show some informations like last version of this board
and the cards ids that are related to this boards, this serializer will show these informations.
"""
last_version = serializers.SerializerMethodField()
cards_ids = serializers.ListField(child=serializers.IntegerField())
def get_last_version(self, instance):
last_version = instance.history.first().prev_record
return HistoricalRecordSerializer(last_version).data
class Meta:
model = Board
fields = '__all__'
what is the best way to solve it? I was thinking in create a get_cards_ids method on serializer and remove annotate, but I don't know how to do it and justing googling it now. rlly don't know if this is the correct way to do it.
Test the view, not the serializer, i.e. remove BoardSerializerRetrieve(board) from your test code.
cards_ids is annotated on ViewSet level. The annotated queryset is then passed to serializer.
#pytest.mark.django_db(databases=['default'])
def test_retrieve_boards(api_client):
board = baker.make(Board)
url = f'{boards_endpoint}{board.id}/'
response = api_client().get(url)
assert response.status_code == 200
Also, instead of building the URL manually with url = f'{boards_endpoint}{board.id}/', consider using reverse, e.g. url = reverse("path-name", kwargs={"pk": board.id}).
There is a possibility to solve my problem, please.
I have 3 molds, of which 2 are related.
I am using create on ModelViewSet, which sent the data but I am getting the following error.
(list indexes must be integer or chunked, not str)
Of course I am trying to create a list of objects, but.
¿How would you develop the syntax? With the use of For?
ModelViewSet
class CreateApiModelViewSet(viewsets.ModelViewSet):
serializer_class = EDFSerializer
def get_queryset(self):
dano = models.Dano.objects.all()
return dano
def create(self, request, *args, **kwargs):
data = request.data
new_evento = models.Evento.objects.create(
tabla=data["evento"]["tabla"],
usuario=models.Usuario.objects.filter(user_id=data["evento"]["usuario"]).first(),
patio=models.Patio.objects.filter(id=data["evento"]["patio"]).first()
)
new_evento.save()
# New Dano
new_dano = models.Dano.objects.create(
evento=new_evento,
observacion=data["observacion"])
new_dano.save()
# Model FotoDano With Error.. :(
foto = []
for fotos in foto:
for f in data["fotodanodetail"]["foto"][0]:
foto_obj = models.FotoDano.objects.get(
foto=data["fotodanodetail"]["foto"],
dano=new_dano)
new_foto_dano.foto.add(foto_obj)
# Comment
# new_foto_dano = models.FotoDano.objects.create(
# #id=data["fotodanodetail"]["id"],
# #foto=data["fotodanodetail"]["foto"],
# dano=new_dano)
# new_foto_dano.save()
serializer = EDFSerializer(new_evento)
return Response(serializer.data)
Serializer
# Import Base64
from drf_extra_fields.fields import Base64ImageField
class EDFSerializer(serializers.ModelSerializer):
fotodanodetail = Base64ImageField(required=False)
evento = CrearEventoSerializer()
fotodanodetail = FotoDanoFiltroSerializer(many=True)
class Meta:
model = models.Dano
fields = ('evento','observacion','fotodanodetail')
Postman
Based on DRF when you have writeable nested serializer best way is override .create method of your serializer rather than viewset
for more information checkout drf docs here
All data in request.data have str type you must cast like int(data["evento"]["usuario"])
Currently working on a web page and I want to show two different tables of information one is for individual foods and the other is for recipes, however I can only get the first class to pull up any information I've tested to see if the first class can pull up the recipe database and it, in fact, currently out of ideas on what to try next.
class SearchFoodResultsView(ListView):
model = Food
template_name = 'nutrihacker/search.html'
context_object_name = 'food_list'
# overrides ListView get_queryset to find names containing search term and pass them to template
def get_queryset(self):
query = self.request.GET.get('term')
if (query == None):
return Food.objects.all()
else: # If there are any foods containing the query, they will be in the resulting object_list which is used by search.html in a for loop
food_list = Food.objects.filter(
Q(name__icontains = query)
)
return food_list
class SearchRecipeResultsView(ListView):
model = RecipePreset
template_name = 'nutrihacker/search.html'
context_object_name = 'recipe_list'
# overrides ListView get_queryset to find names containing search term and pass them to template
def get_queryset(self):
query = self.request.GET.get('term')
if (query == None):
return RecipePreset.objects.all()
else: # If there are any recipes containing the query, they will be in the resulting object_list which is used by search.html in a for loop
recipe_list = RecipePreset.objects.filter(
Q(name__icontains = query)
)
return recipe_list
I want delete serializer's content to show.I am using Django Rest Framework.I am making a system return Json of serializers.Furthermore,I did not want to show user_id data. I wrote in views.py
class InfoViews(viewsets.ModelViewSet):
queryset = Info.objects.all()
serializer_class = InfoSerializer
lookup_field = 'id'
def update(self,request, *args, **kwargs):
obj = UserInfo.objects.get(pk=kwargs['id'])
data = request.data
info_serializers = InfoSerializer(obj, data = data)
if info_serializers.is_valid(raise_exception=True):
info_serializers.save()
del info_serializers.data['user_id']
return JsonResponse(info_serializers.data)
Now all son data is shown.What is wrong in my code?How should I fix this?
You can specify in the serializers which fields you want to include or exclude in the response:
http://www.django-rest-framework.org/api-guide/serializers/#specifying-which-fields-to-include
look for : Specifying which fields to include
hope this helpes
First Clone the object into a new variable and then pop the key.
if info_serializers.is_valid(raise_exception=True):
info_serializers.save()
import copy
new = copy.deepcopy(info_serializers.data)
new.pop('user_id', None)
return JsonResponse(new)
As a Django newbie, I am trying to return JSON Objects from two models with each object containing the username, id, ticketID. Right now the code is simply putting the lists together without indexing. I should point out that there is a relationship between user and ticket so that can be traversed also.
{"username":"Paul","id":2}, {"username":"Paul","id":2}, {"username":"Ron","id":19}, {"id":"1c6f039c"}, {"id":"6480e439"},
{"id":"a97cf1s"}
class UsersforEvent(APIView):
def post(self, request):
body_unicode = request.body.decode('utf-8')
body = json.loads(body_unicode)
value = body['event']
queryset = Ticket.objects.filter(event = value)
referenced_users = User.objects.filter(ticket_owner__in=queryset.values('id'))
result_list = list(itertools.chain(referenced_users.values('username', 'id'), queryset.values('id')))
return Response((result_list))
You should do a single query to get the ticket with the related user for each one, then create the list of dicts from there. Assuming your Ticket model has an "owner" field which is a FK to User:
queryset = Ticket.objects.filter(event=value).select_related('owner')
result_list = [{'ticket_id': ticket.id, 'username': ticket.owner.username, 'user_id': ticket.owner.id}
for ticket in queryset]
(Note, this shouldn't be the action of a POST though; that is for changing data in the db, not querying.)