i have to api views that use a model. i tried use headlines.objects.all() to get everything in the model and the second view is supposed to get only the title field from the model, i have tried filtering and i got a positional argument error. this is my views file.
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from news.models import Headline
from news.api.serializers import *
#api_view(['GET',])
def api_detail(request, any):
try:
qs = Headline.objects.get(slug=any)
except Headline.DoesNotExist:
return Response(status = status.HTTP_404_NOT_FOUND)
if request.method == "GET":
serializer = HeadlineSerializer(qs)
return Response(serializer.data)
#api_view(['GET',])
def api_head(request):
try:
py = Headline.objects.all().filter(title=title).order_by('-id')
except Headline.DoesNotExist:
return Response(status = status.HTTP_404_NOT_FOUND)
if request.method == "GET":
serializer = HeadlineSerializer(py, many=True)
return Response(serializer.data)
This is my serializers.py file
from rest_framework import serializers
from news.models import Headline
class HeadlineSerializer(serializers.ModelSerializer):
class Meta:
model = Headline
fields = ['title', 'contentt']
here is my urls.py
from django.urls import path
from news.api.views import *
app_name = 'news'
urlpatterns = [
path('<slug:any>/', api_detail, name='details'),
path('', api_head, name='api_head'),
]
The problem is at this line:
py = Headline.objects.all().filter(title=title).order_by('-id')
title is not a variable defined here.
If i understood you right you want to get just the field title, so you would get a response like:
[
{
"title": "lorem"
},
{
"title": "ipsum"
},
]
To achieve this you could create another serializer for that view.
class HeadlineSerializer(serializers.ModelSerializer):
class Meta:
model = Headline
fields = ['title', 'contentt']
class HeadlineTitleSerializer(serializers.ModelSerializer):
class Meta:
model = Headline
#fields will filter you response for which fields you want to return in the response.
fields = ['title']
In you view:
#api_view(['GET',])
def api_detail(request, any):
try:
qs = Headline.objects.get(slug=any)
except Headline.DoesNotExist:
return Response(status = status.HTTP_404_NOT_FOUND)
if request.method == "GET":
serializer = HeadlineSerializer(qs)
return Response(serializer.data)
#api_view(['GET',])
def api_head(request):
py = Headline.objects.all().order_by('-id')
if request.method == "GET":
serializer = HeadlineTitleSerializer(py, many=True)
return Response(serializer.data)
Related
I'm trying to parse the JSON data nad import it to the database through API. I think I almost got it but still getting this message: {'field': [ErrorDetail(string='This field is required.', code='required')] from my HttpResponse and I don't really know what to do with it.
Here is my code:
models.py
from django.db import models
class Data(models.Model):
name = models.CharField(max_length=255, blank=False)
eid = models.DecimalField(max_digits=10, decimal_places=0, blank=False)
data = models.TextField(max_length=800, blank=True)
def __str__(self):
return "ID: {} -- Name: {}".format(self.eid, self.name)
serializers.py
I honestly think that the problem is in the serializers but can't figure it out what to add here.
from .models import Data
from rest_framework import serializers
class DataSerializer(serializers.ModelSerializer):
class Meta:
model = Data
fields = ['name', 'eid', 'data']
class DetailSerializer(serializers.ModelSerializer):
class Meta:
model = Data
fields = '__all__'
views.py
Here I must have 3 views. First for Import. Second for show basic data like name, id, etc. which are given from the JSON file I provide to import/ API. And third for full details of the data given from the JSON file.
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse, HttpResponse
from rest_framework.parsers import JSONParser
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.exceptions import ParseError
from rest_framework.authentication import BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from .serializers import DataSerializer, DetailSerializer
from .models import Data
#csrf_exempt
#api_view(['POST'])
#permission_classes([IsAuthenticated])
#authentication_classes([BasicAuthentication])
#IMPORT VIEW
def import_data(request):
if request.method == 'POST':
try:
data = JSONParser().parse(request)
serializer = DataSerializer(data=data, many=True)
serializer.is_valid()
except ParseError:
return JsonResponse({"detail":"DATA YOU IMPORTED ARE NOT JSON DATA"}, safe=False, status=400)
except KeyError:
return JsonResponse({"detail":"NAME AND ID MUST BE INCLUDED"}, safe=False, status=400)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, safe=False, status=201)
else:
return HttpResponse(serializer.errors)
else:
return JsonResponse({"detail":"ACCEPTING ONLY POST REQUESTS"}, safe=False, status=400)
#csrf_exempt
#api_view(['GET'])
def data_view(request, name):
if request.method == 'GET':
data = Data.objects.filter(name__iexact=name)
if data:
serializer = DataSerializer(data, many=True)
serializer.is_valid()
return JsonResponse(serializer.data, safe=False, status=200)
else:
return JsonResponse({"detail":"NO DATA FOUND"}, safe=False, status=404)
else:
return JsonResponse({"detail":"ACCEPTING ONLY GET REQUESTS"}, safe=False, status=400)
#csrf_exempt
#api_view(['GET'])
def data_details(request, name, eid):
if request.method == 'GET':
data = Data.objects.filter(name__iexact=name, eid=eid)
if data:
serializer = DetailSerializer(data['eid'], many=False)
# serializer.is_valid()
return JsonResponse(serializer.data, status=200)
else:
return JsonResponse({"details":"DATA NOT FOUND"}, safe=False, status=404)
else:
return JsonResponse({"details":"ACCEPTING ONLY GET REQUESTS"}, safe=False, status=400)
Thank you for any help <3.
A sample for class view:
from rest_framework.response import Response
from rest_framework.views import APIView
class ImportDataView(APIView):
queryset = Data.objects.all()
serializer_class = DataSerializer
permission_classes = (IsAuthenticated,)
authentication_classes = (BasicAuthentication,)
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
import_data = ImportDataView.as_view()
Problem: I trying to path like this --> path('Image/<str>', views.getImage, name='imageCategory'),
to get image filter by category --> http://127.0.0.1:8000/Image/TV
#-->Model.py
from django.db import models
class Post(models.Model):
Topic = models.CharField(max_length=250, default='')
Desc = models.CharField(max_length=750, default='')
Link = models.TextField(default='')
def __str__(self):
return str(self.Topic)
class Category(models.Model):
categoryName = models.CharField(max_length=50, default='')
def __str__(self):
return str(self.categoryName)
class PostImage(models.Model):
post = models.ForeignKey(
Post, on_delete=models.CASCADE, null=True, related_name='post_name')
category = models.ForeignKey(
Category, on_delete=models.CASCADE, null=True, related_name='category_name')
images = models.FileField(upload_to='images/')
def __str__(self):
return str(self.post)
#-->Serializer.py
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import Post, PostImage
class BlogSerializer(ModelSerializer):
class Meta:
model = Post
fields = '__all__'
class ImageSerializer(ModelSerializer):
topic_link = serializers.CharField(source='post.Link', read_only=True)
Category = serializers.CharField(source='category', read_only=True)
class Meta:
model = PostImage
fields = '__all__'
#-->view.py
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Post, PostImage
from .Serializer import BlogSerializer, ImageSerializer
# Create your views here.
#api_view(['GET'])
def getNames(request):
Blog = Post.objects.all()
serializer = BlogSerializer(Blog, many=True)
return Response(serializer.data)
#api_view(['GET'])
def getName(request, pk):
Blog = Post.objects.get(id=pk)
serializer = BlogSerializer(Blog, many=False)
return Response(serializer.data)
#my problem part
#api_view(['GET'])
def getImage(request):
image = PostImage.objects.get(Category=request.Category)
serializer = ImageSerializer(image, many=True)
return Response(serializer.data)
#-->urls.py
from django.urls import path
from . import views
urlpatterns = [
path('blogs/', views.getNames, name='blog'),
path('blogs/<pk>', views.getName, name='blog'),
path('Image/', views.getImage, name='image'),
path('Image/<str>', views.getImage, name='imageCategory'),
]
First, you need to set the parameter name in urls.py.
urlpatterns = [
...
path('Image/', views.getImages, name='image'),
path('Image/<str:category>', views.getImage, name='imageCategory'),
]
Here the category should be the categoryName value of the Category model.
Next, in views.py, you need to pass that parameter to the getImage function.
And also you need to add getImages function for the case of no category.
#api_view(['GET'])
def getImage(request, category):
image = PostImage.objects.filter(category__categoryName=category)
serializer = ImageSerializer(image, many=True)
return Response(serializer.data)
#api_view(['GET'])
def getImages(request):
image = PostImage.objects.all()
serializer = ImageSerializer(image, many=True)
return Response(serializer.data)
I am getting this error Object of type ProductImage is not JSON serializable
I am trying to make model in which I can add multiple images using ManytoManyFeild().and I then I want to serialize it so that I can send it to and show on frontend page.
here is my models:
from django.db import models
class Product(models.Model):
id = models.IntegerField(unique=True,primary_key=True)
title = models.CharField(max_length=200)
description = models.TextField(max_length= 100000 ,null=True, blank=True)
price = models.FloatField()
count = models.IntegerField(default=1)
file_content = models.ManyToManyField("ProductImage", related_name='file_content', blank=True, null=True)
offer= models.BooleanField(default=False)
def __str__(self):
return self.title
class ProductImage(models.Model):
property_id = models.ForeignKey(Product,on_delete=models.CASCADE ,null=True, blank=True)
media = models.FileField(upload_to='pics')
def __str__(self):
return '%s-image' % (self.property_id.title)
and here is my serializer.py:
from rest_framework import serializers
from . models import Product, ProductImage
class ProductImageSerializer(serializers.ModelSerializer):
class Meta:
model = ProductImage
fields = [ 'property_id','media']
class ProductSerializer(serializers.ModelSerializer):
file_content = ProductImageSerializer(many=True)
class Meta:
model = Product
fields = ['id', 'title','description', 'price','count', 'file_content',
'offer']
extra_kwargs = {
"file_content": {
"required": False,
}
}
and here is my Views.py:
from rest_framework.serializers import Serializer
from . models import Product, ProductImage
from rest_framework.response import Response
from . serializer import ProductSerializer
from rest_framework import status
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.decorators import api_view, permission_classes, parser_classes
from rest_framework.permissions import IsAuthenticated
#api_view(['POST','GET'])
#permission_classes([IsAuthenticated])
#parser_classes([MultiPartParser, FormParser])
def ProductViews(request):
if request.method == 'POST':
files = request.FILES.getlist('file_content')
if files:
request.data.pop('file_content')
serializer = ProductSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
tweet_qs = Product.objects.get(id=serializer.data['id'])
uploaded_files = []
for file in files:
content = ProductImage.objects.create(media=file)
uploaded_files.append(content)
tweet_qs.file_content.add(*uploaded_files)
context = serializer.data
context["file_content"] = [file.id for file in uploaded_files]
return Response(context, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
serializer = ProductSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
context = serializer.data
return Response(context, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'GET':
detail = [{"title": detail.title, "id": detail.id, "count": detail.count, "description": detail.description, "price": detail.price, "offer": detail.offer , "details": detail.file_content.all()}
for detail in Product.objects.all()]
return Response(detail)
I don't what's wrong so I will be very grateful to you if can help. Thanks
Note:If you know any other better way to make a Json that can include a list of images, you can also share it(or its link).
This may help you:
class ProductImage(models.Model):
property_id = models.ForeignKey(Product, on_delete=models.CASCADE ,null=True, blank=True)
media = models.FileField(upload_to='pics')
def __str__(self):
return '%s-image' % (self.property_id.title)
def media_url(self):
return self.media.url
class ProductImageSerializer(serializers.ModelSerializer):
class Meta:
model = ProductImage
fields = [ 'property_id','media','media_url']
how can I fix this issue?
the page runs perfectly. when I do post the post. it posts but when I want to type the comment and send by 'GET' I get this error. so, how can I ignore this error this my first question?
- also, I need anyone to give me the best way to make a relationship between post and comment
models.py
from django.db import models
from django.contrib.auth.models import User
class Publication(models.Model):
title = models.CharField(max_length=30)
class Meta:
ordering = ['title']
def __str__(self):
return self.title
class Article(models.Model):
publications = models.ManyToManyField(Publication)
headline = models.CharField(max_length=100)
class Meta:
ordering = ['headline']
def __str__(self):
return self.headline
class Post(models.Model):
users = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
question = models.TextField(max_length=500)
def __str__(self):
return self.title
class Comment(models.Model):
posts = models.ForeignKey(Post, on_delete=models.CASCADE)
comment = models.TextField(max_length=500)
def __str__(self):
return self.comment
views.py
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from .models import Post, Comment
from .forms import PostForm, CommentForm
def index(request):
# All questions
posts = Post.objects.all()
return render(request, 'community/index.html', {'posts': posts})
def post_view(request):
post_form = PostForm
context = {'posted': post_form}
# Create post
if request.method == 'GET':
post_form = PostForm(request.GET)
if post_form.is_valid():
user_post = post_form.save(commit=False)
user_post.title = post_form.cleaned_data['title']
user_post.question = post_form.cleaned_data['question']
post = Post.objects.create(users=User.objects.get(username=request.user), title=user_post.title, question=user_post.question)
post.save()
return redirect('community:index')
return render(request, 'community/post.html', context)
def answers(request, post_id):
# Specific post
posts = Post.objects.get(id=post_id)
# Create comment
comment_form = CommentForm
context = {'posts': posts, 'comment_form': comment_form}
if request.method == 'GET':
comment_form = CommentForm(request.GET)
if comment_form.is_valid():
user_comment = comment_form.save(commit=False)
user_comment.comment = comment_form.cleaned_data['comment']
user_comment.save()
return render(request, 'community/answers.html', context)
urls.py
from django.urls import path
from . import views
app_name = 'community'
urlpatterns = [
path('', views.index, name='index'),
path('post/', views.post_view, name='post'),
path('answers/<int:post_id>', views.answers, name='answers'),
]
forms.py
from .models import Post, Comment
from django import forms
from django.contrib.auth.models import User
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
exclude = ['users']
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = '__all__'
exclude = ['users', 'posts']
You forgot to assign the post, or the post_id of the comment you created:
def answers(request, post_id):
# Specific post
posts = Post.objects.get(id=post_id)
# Create comment
comment_form = CommentForm
context = {'posts': posts, 'comment_form': comment_form}
if request.method == 'GET':
comment_form = CommentForm(request.GET)
if comment_form.is_valid():
comment_form.instance.post_id = post_id
user_comment = comment_form.save()
# …
That being said, the above view does not really respect the HTTP assumptions. A view that makes a GET request is not supposed to change entities, so if you want to create a comment, you need to do that through a POST request. Furthemore in order to implement the Post/Redirect/Get pattern [wiki] a successful POST request should return a redirect response.
I was following along with this tutorial here:
https://realpython.com/test-driven-development-of-a-django-restful-api/
I have set everything up and the API endpoints are working as expected:
When I call:
localhost/api/v1/puppies/
returned:
{
"name": "Bridgett",
"age": 3,
"breed": "Boxer",
"color": "White",
"created_at": "2018-10-03T17:28:21.333893Z",
"updated_at": "2018-10-03T17:34:13.899385Z"
},
{
"name": "Mia",
"age": 3,
"breed": "Mix",
"color": "Black",
"created_at": "2018-10-09T16:08:59.775685Z",
"updated_at": "2018-10-09T16:08:59.775685Z"
}
Also the main issue which is the Detail view works as well...
If I call: localhost/api/v1/puppies/2 returns:
{
"name": "Bridgett",
"age": 3,
"breed": "Boxer",
"color": "White",
"created_at": "2018-10-03T17:28:21.333893Z",
"updated_at": "2018-10-03T17:34:13.899385Z"
}
Which is great and all of my put post delete works as well here is the code:
models.py:
# models.py
from django.db import models
class Puppy(models.Model):
"""
Puppy Model
Defines the attributes of a puppy
"""
name = models.CharField(max_length=255)
age = models.IntegerField()
breed = models.CharField(max_length=255)
color = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
def get_breed(self):
return self.name + ' belongs to ' + self.breed + ' breed.'
def __repr__(self):
return self.name + ' is added.'
serializers.py
# serializers.py
from rest_framework import serializers
from .models import Puppy
class PuppySerializer(serializers.ModelSerializer):
class Meta:
model = Puppy
fields = ('name', 'age', 'breed', 'color', 'created_at', 'updated_at')
views.py
from django.shortcuts import render
from rest_framework.decorators import api_view
# from rest_framework.decorators import APIView
from rest_framework.response import Response
from rest_framework import status
from django.views.generic import TemplateView
from .models import Puppy
from .serializers import PuppySerializer
#api_view(['GET', 'DELETE', 'PUT'])
def get_delete_update_puppy(request, pk):
try:
puppy = Puppy.objects.get(pk=pk)
except Puppy.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
# get details of a single puppy
if request.method == 'GET':
serializer = PuppySerializer(puppy)
return Response(serializer.data)
# update details of a single puppy
if request.method == 'PUT':
serializer = PuppySerializer(puppy, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_204_NO_CONTENT)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# delete a single puppy
if request.method == 'DELETE':
puppy.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
#api_view(['GET', 'POST'])
def get_post_puppies(request):
# get all puppies
if request.method == 'GET':
puppies = Puppy.objects.all()
serializer = PuppySerializer(puppies, many=True)
return Response(serializer.data)
# insert a new record for a puppy
if request.method == 'POST':
data = {
'name': request.data.get('name'),
'age': int(request.data.get('age')),
'breed': request.data.get('breed'),
'color': request.data.get('color')
}
serializer = PuppySerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(
r'^api/v1/puppies/(?P<pk>[0-9]+)$',
# views.PuppyDetail.as_view(),
views.get_delete_update_puppy,
name='get_delete_update_puppy'
),
url(
r'^api/v1/puppies/$',
# views.PuppyList.as_view(),
views.get_post_puppies,
name='get_post_puppies'
)
]
All this works as expected however the issue I am having is when I replace the code in views.py and urls.py like so to use class based views I get nothing returned in the detail view api call: localhost/api/v1/puppies/2 returns:
{
"name": "",
"age": null,
"breed": "",
"color": ""
}
The updated code is this:
views.py
from django.shortcuts import render
# from rest_framework.decorators import api_view
from rest_framework.decorators import APIView
from rest_framework.response import Response
from rest_framework import status
from django.views.generic import TemplateView
from .models import Puppy
from .serializers import PuppySerializer
class PuppyDetail(APIView):
"""
Get, update, or delete a single puppy instance
"""
def get_object(self, pk):
try:
puppy = Puppy.objects.get(pk=pk)
except Puppy.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
def get(self, request, pk):
# get details of a single puppy
puppy = self.get_object(pk)
serializer = PuppySerializer(puppy)
return Response(serializer.data)
def put(self, request, pk):
# update details of a single puppy
puppy = self.get_object(pk)
serializer = PuppySerializer(puppy, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_204_NO_CONTENT)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
puppy = self.get_object(pk)
puppy.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class PuppyList(APIView):
"""
List all puppies, or create a new puppy
"""
def get(self, request):
puppies = Puppy.objects.all()
serializer = PuppySerializer(puppies, many=True)
return Response(serializer.data)
def post(self, request):
serializer = PuppySerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(
r'^api/v1/puppies/(?P<pk>[0-9]+)$',
views.PuppyDetail.as_view(),
# views.get_delete_update_puppy,
# name='get_delete_update_puppy'
),
url(
r'^api/v1/puppies/$',
views.PuppyList.as_view(),
# views.get_post_puppies,
# name='get_post_puppies'
)
]
My question is what is the disconnect that my api calls are not working once I implement the class based views?
After debugging with prints I realized that I did not add a return to get_object:
def get_object(self, pk):
try:
puppy = Puppy.objects.get(pk=pk)
return(puppy) # This needed to be added.
except Puppy.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
I was missing a return of the object to send to the function call. Thanks