Send information with the post method in the rest framework - django

I want to add a new comment with the post method, but it gives an error
{'non_field_errors': [ErrorDetail(string='Invalid data. Expected a dictionary, but got ModelBase.', code='invalid')]}
Serializers :
from rest_framework import serializers
from .models import Products,ProductsComments
class ProdcutsSerializers(serializers.ModelSerializer):
colors = serializers.SlugRelatedField(many=True,read_only=True,slug_field='name')
category = serializers.SlugRelatedField(many=True,read_only=True,slug_field='name')
sizes = serializers.SlugRelatedField(many=True,read_only=True,slug_field='name')
class Meta:
model = Products
fields = '__all__'
class ProductsCommentsSerializers(serializers.ModelSerializer):
user = serializers.SlugRelatedField(many=True,read_only=True,slug_field='id')
product = serializers.SlugRelatedField(many=True,read_only=True,slug_field='id')
class Meta:
model = ProductsComments
fields = '__all__'
Views :
from rest_framework.decorators import api_view,permission_classes
from rest_framework.response import Response
from rest_framework import status
from .serializers import *
from .models import *
#api_view(['GET'])
def products_list(request):
products = Products.objects.all()
data = ProdcutsSerializers(products,many=True).data
return Response(data)
#api_view(['GET'])
def products_comments_list(request):
products_comments = ProductsComments.objects.all()
data = ProductsCommentsSerializers(products_comments,many=True).data
return Response(data)
#api_view(['POST'])
def products_comments_add(request):
data = ProductsCommentsSerializers(data=ProductsComments)
if data.is_valid():
print('Ok')
else:
print('not')
#print(data)
print(data.errors)
return Response({"M": "not"})

Related

How to POST multiple data in DRF and React with Axios

I have 2 models named Recipe and Step..
I have serialized both to make an API for GET request.. I want to know is there a way to create for POST request so that I can send both the data (steps and recipe) in the same request?
models.py:
from django.db import models
class Recipe(models.Model):
title = models.CharField( max_length=50)
uuid = models.CharField( max_length=100)
def __str__(self):
return f'{self.uuid}'
class Step(models.Model):
step = models.CharField(max_length=300)
uuid = models.ForeignKey(Recipe, on_delete=models.CASCADE)
def __str__(self):
return f'{self.step} - {self.uuid}'
serializers.py:
from rest_framework import serializers
from .models import *
class RecipeSerializer(serializers.ModelSerializer):
class Meta:
model = Recipe
fields = ['title', 'uuid']
class StepSerializer(serializers.ModelSerializer):
class Meta:
model = Step
fields = ['step', 'uuid']
views.py:
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import *
from .models import *
#api_view(['GET'])
def apiOverview(request):
api_urls = {
'List':'/recipe-list/',
'Detail View':'/recipe-detail/<str:pk>/',
'Create':'/recipe-create/',
'Update':'/recipe-update/<str:pk>/',
'Delete':'/recipe-delete/<str:pk>/',
'Steps' : '/steps/<str:pk>'
}
return Response(api_urls)
#api_view(['GET'])
def recipeList(request):
recipes = Recipe.objects.all()
serializer = RecipeSerializer(recipes, many=True)
return Response(serializer.data)
#api_view(['GET'])
def recipeDetail(request, pk):
recipe = Recipe.objects.get(uuid=pk)
recipe_serializer = RecipeSerializer(recipe, many=False)
steps = Step.objects.filter(uuid=pk)
steps_serializer = StepSerializer(steps, many=True)
return Response({
'recipe' : recipe_serializer.data,
'steps' : steps_serializer.data
})
How can I create a view for POST and handle both the models?
Try:
from rest_framework import generics
from .models import *
class StepAndRecipe(generics.CreateAPIView):
queryset = Step.objects.all()
queryset = Recipe.objects.all()
serializer_class = StepSerializer
serializer_class = RecipeSerializer
Add in urls.py:
from django.urls import path
from .views import StepAndRecipe
urlpatterns = [
path('steprecipepost', StepAndRecipe.as_view(), name='steps_recipes')
This will only work with POST! And one more thing: take care with the raw data and the HTML form, maybe theses get a little confused since you are using two models in the same view.

How to count rows on PostgreSQL database in Django?

How to count rows on PostgreSQL database in Django and show using highchart?
Example: I want to show how much record/row from 7.00am to 7.00 am next day.
models:
from django.db import models
from datetime import datetime, date
class hujan(models.Model):
id = models.AutoField(primary_key=True)
tanggal = models.DateTimeField(auto_now_add=True)
dtinms = models.IntegerField()
hujan = models.FloatField()
serializers:
from rest_framework import serializers
from .models import hujan, cahayasuhukelembapan
class hujanSerializer(serializers.ModelSerializer):
class Meta:
model = hujan
fields = ('tanggal','dtinms','hujan')
views:
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, JsonResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.renderers import TemplateHTMLRenderer
from .models import hujan
from .serializers import hujanSerializer
def homePageView(request):
return render(request,'homepage.html')
class hujanlistall(APIView):
def get(self, request):
Hujan = hujan.objects.all()
serializer = hujanSerializer(Hujan, many=True)
return JsonResponse(serializer.data,safe=False)
Modify "views.py" file,
import datetime
class hujanlistall(APIView):
def get(self, request):
Hujan = hujan.objects.filter(tanggal__range = (datetime.datetime.combine(start_date,datetime.time.min),datetime.datetime.combine(end_date, datetime.time.max)))
RowCount = len(Hujan)
serializer = hujanSerializer(Hujan, many=True)
return JsonResponse(serializer.data,safe=False)

Django Restful API Design Validation Logic

Here I have an endpoint to create media content for users. The endpoint works, but I have a feeling my design implementation is incorrect.
Should validation logic be contained in serializers create? Is this bad practice? I attempted to move validation logic to models.py, but ran into issues with accessing the model, specifically this line - self.model(user=user, category=category).
view.py
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .models import UserMedia
from .renderers import UserMediaSerializerJSONRenderer
from .serializers import UserMediaSerializer
class UserMediaCreateAPIView(APIView):
permission_classes = (IsAuthenticated,)
renderer_classes = (UserMediaSerializerJSONRenderer,)
serializer_class = UserMediaSerializer
def post(self, request):
userMedia = request.data.get('userMedia', {})
serializer = self.serializer_class(data=userMedia)
serializer.is_valid(raise_exception=True)
serializer.save(user=request.user, category=userMedia['category'])
return Response(serializer.data, status=status.HTTP_201_CREATED)
serializers.py
from rest_framework import serializers
from .models import UserMedia
class UserMediaSerializer(serializers.ModelSerializer):
category = serializers.CharField(allow_blank=False, required=True)
class Meta:
model = UserMedia
fields = ('category',)
read_only_fields = ('category',)
def get_category(self, obj):
if obj.category:
return obj.category
return 'N/A'
def create(self, validated_data):
if validated_data['user'] is None:
raise TypeError('User media must have a user')
if validated_data['category'] is None:
raise TypeError('User media must have a category.')
if validated_data['category'] not in dict(UserMedia.CATEGORY_CHOICES):
raise TypeError('User media category is not available.')
userMedia = UserMedia(**validated_data)
userMedia.save()
return userMedia
models.py
from django.db import models
class UserMedia(models.Model):
user = models.ForeignKey('authentication.User', on_delete=models.CASCADE, related_name='media')
MUSIC = 'M'
VIDEO = 'V'
CATEGORY_CHOICES = (
(MUSIC, 'Music'),
(VIDEO, 'Video'),
)
category = models.CharField(max_length=1, choices=CATEGORY_CHOICES, blank=False)
The validation should be done in your view. The serializers should just be for serializing data. The validation should be done in your view then the serializer is called from your view. As far as this line self.model(user=user, category=category) is concerned it does not appear that you ever import user any where.

How to test DRF serializer when using additional keyword arguments?

I have a simple model and a serializer which uses additional keyword arguments(extra_kwargs) to limit max and min value for a field. I want to write two test cases in my tests.py to both test valid and invalid values for that field (weight). How should I do this?
I am using Python 2.7.
Model
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=100)
weight = models.FloatField()
Serializer
from rest_framework import serializers
from .models import Person
class PersonSerializer(serializers.ModelSerializer):
model = Person
fields = ('name', 'weight')
extra_kwargs = {'weight': {'min_value': 5, 'max_value': 1000}}
tests.py
from django.test import TestCase
from .models import Person
class ModelTestCase(TestCase):
def setUp(self):
self.person = Person(name='Sam', weight=150)
def test_when_weight_isValid(self):
#e.g. when weight = 200
def test_when_weight_notValid(self):
#e.g. when weight = 3
import json
from django.urls import reverse
from django.contrib.auth import authenticate
from rest_framework import status
from rest_framework.test import APITestCase
from .models import *
class UserTests(APITestCase):
def setUp(self):
self.person = Person(name='Sam', weight=150)
def test_when_weight_isvalid(self):
url = reverse('person-detail', kwargs={'pk': self.person.id})
data = {'weight': 200}
response = self.client.patch(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
print json.dumps(response.data, ensure_ascii=False, indent=2)
Something like this,code is untest.

Question On Django Form Models

I am working on form models and get this error:
global name 'AdForm' is not defined
In my view I have:
from django.template import RequestContext, loader
from django.http import HttpResponse
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
from django import forms
#login_required
def create(request):
if request.POST:
ad = AdForm(request.POST)
if ad.is_valid():
test = 'valid'
else:
test = 'invalid'
else:
test = 'none'
template = loader.get_template('ads/create.html')
context = RequestContext(request, {
'test': test
})
return HttpResponse(template.render(context))
However it is not picking up my model. My model in my view is:
from django.db import models
from django.forms import ModelForm
TYPE_CHOICES = (
'Image',
'Code',
)
SIZE_CHOICES = (
'Leaderboard',
'Banner',
'Skyscraper',
'Square',
)
class Ad(models.Model):
title = models.CharField(max_length=40)
type = models.CharField(max_length=7)
size = models.CharField(max_length=16)
clicks = models.IntegerField()
media = models.ImageField(upload_to='ads')
link = models.URLField(null=True)
created = models.DateTimeField(auto_now_add=True)
expires = models.DateTimeField(null=True)
def __unicode__(self):
return self.name
class AdForm(ModelForm):
class Meta:
model = Ad
Does anyone know why it is not picking up the form model?
Thanks from a noob.
At the top of your view, you need:
from .models import AdForm
Also, forms usually go in forms.py, not with the models.