When I try to retrieve all data from my REST API I get them correctly except from one field, that is the field 'name' from Skill class. Instead of the 'name' I get only its id. Can you help me to resolve this?----------------------------------------------
here is the output
Here is the code:
models.py
from django.db import models
from django.forms import ImageField
from django.utils.text import slugify
class Skill(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Project(models.Model):
title = models.CharField(max_length=200)
sub_title = models.CharField(max_length=200, null=True, blank=True)
front_page = models.ImageField(null=True, blank=True, upload_to="images", default="broken-image.png")
body = models.TextField(null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
skills = models.ManyToManyField(Skill, null=True)
slug = models.SlugField(null=True, blank=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if self.slug == None:
slug = slugify(self.title)
has_slug = Project.objects.filter(slug=slug).exists()
count = 1
while has_slug:
count += 1
slug = slugify(self.title) + '-' + str(count)
has_slug = Project.objects.filter(slug=slug).exists()
self.slug = slug
super().save(*args, **kwargs)
serializers.py
from rest_framework import serializers
from project.models import Project, Skill
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from project.models import Project, Skill
from .serializers import ProjectSerializer
from rest_framework import status
from django.shortcuts import get_object_or_404
#api_view(['GET'])
def getData(request):
project = Project.objects.all()
serializer = ProjectSerializer(project, many=True)
return Response(serializer.data)
#api_view(['POST'])
def create(request):
serializer= ProjectSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
#api_view(['POST'])
def update(request, pk):
item = Project.objects.get(pk=pk)
serializer = ProjectSerializer(instance=item, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(status=status.HTTP_404_NOT_FOUND)
#api_view(['DELETE'])
def delete(request, pk):
item = get_object_or_404(Project, pk=pk)
item.delete()
return Response(status=status.HTTP_202_ACCEPTED)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.getData),
path('create/', views.create),
path('update/<int:pk>/', views.update),
path('<int:pk>/delete/', views.delete),
]
Use a SlugRelatedField [drf-doc] to specify that you want to use the name of the skills, so:
from rest_framework import serializers
from project.models import Project, Skill
class ProjectSerializer(serializers.ModelSerializer):
skills = serializers.SlugRelatedField(
many=True, slug_field='name', queryset=Skill.objects.all()
)
class Meta:
model = Project
fields = '__all__'
The nice thing of such SlugRelatedField is that this can work bidrectional: not only can you serialize data, but you can also use it to specify skills and thus create or update Projects.
You need to provide a SkillSerializer and refer to it in your ProjectSerializer. Also, it is better to specify the fields you want in your serializers explicitly, as __all__ may expose the fields you don't want to expose or cause unwanted database queries.
https://www.django-rest-framework.org/api-guide/relations/#nested-relationships
Related
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 trying to make a dynamic search but cant seem to filter queryset by slug. I have tried just about everything and went through stackoverflow questions and nothing seems to solve it. I have tried changing the keyword to "id" and "category" and I get a result but not on slug.
Here is the error/no queryset I received.
This is the filter I made for authors which seems to work.
Here is the code, Please inform if I need to provide more code to understand the problem as this is my first question here. Thanks!
blog_api/views.py
from rest_framework import generics
from blog.models import Post
from .serializers import PostSerializer
from rest_framework.permissions import SAFE_METHODS, IsAuthenticated, IsAuthenticatedOrReadOnly, BasePermission, IsAdminUser, DjangoModelPermissions
from rest_framework import viewsets
from rest_framework import filters
from django.shortcuts import get_object_or_404
from rest_framework.response import Response
class PostUserWritePermission(BasePermission):
message = 'Editing posts is restricted to the author only.'
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
return obj.author == request.user
class PostList(generics.ListAPIView):
permission_classes = [IsAuthenticated]
# queryset = Post.objects.all()
serializer_class = PostSerializer
def get_queryset(self):
user = self.request.user
return Post.objects.filter(author=user)
class PostDetail(generics.RetrieveAPIView, PostUserWritePermission):
# permission_classes = [PostUserWritePermission]
queryset = Post.objects.all()
serializer_class = PostSerializer
def get_queryset(self):
item = self.kwargs["pk"]
print(item)
return Post.objects.filter(slug=item)
blog_api/urls.py
from .views import PostList, PostDetail
from django.urls import path
from rest_framework.routers import DefaultRouter
app_name = 'blog_api'
# router = DefaultRouter()
# router.register('', PostList, basename='post')
# urlpatterns = router.urls
urlpatterns = [
path('posts/<str:pk>/', PostDetail.as_view(), name='detail_create'),
path('', PostList.as_view(), name='list_create'),
]
blog/models.py
from django.db import models
from django.conf import settings
from django.utils import timezone
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Post(models.Model):
class PostObjects(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(status="published")
options = (
("draft", "Draft"),
("published", "Published"),
)
category = models.ForeignKey(Category, on_delete=models.PROTECT, default=1)
title = models.CharField(max_length=250)
excerpt = models.TextField(null=True)
content = models.TextField()
slug = models.SlugField(max_length=250, unique_for_date="published")
published = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="blog_post")
status = models.CharField(max_length=10, choices=options, default="published")
objects = models.Manager()
post_objects = PostObjects()
class Meta:
ordering = ["-published"]
def __str__(self):
return self.title
in your PostDetail class in blog_api/views.py file, instead of overriding get_queryset method, override get_object method, like this
def get_object(self, queryset=None, **kwargs):
item = self.kwargs.get('pk')
return get_object_or_404(Post.objects.filter(slug=item))
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']
I want to know how to make category page view using class based view I know how to make this in function based view by using get_object_or_404(category, slug=None) But I am confused how to do this it in class based views. I tried to google this but I am unable to find anything related to this in class view.
I know I could have used function based view but I have used class based view in whole project so I thought to use them here as well
my code
models.py
from django.db import models
from django.utils import timezone
from slugger import AutoSlugField
from django.contrib.auth.models import User
from django.urls import reverse
# Create your models here.
def upload_location(instance, filename):
return "%s/%s" %(instance.slug, filename)
class Category(models.Model):
title = models.CharField(max_length= 60)
slug = AutoSlugField(populate_from='title')
parent = models.ForeignKey('self',blank=True, null=True ,related_name='children',on_delete=models.CASCADE)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
class Meta:
verbose_name_plural = 'categories'
def __unicode__(self):
return self.title
def __str__(self):
return self.title
def get_absolute_url(self, slug=None):
return reverse("posts-detail", kwargs={"slug": self.slug})
class Post(models.Model):
title = models.CharField(max_length=120)
slug = AutoSlugField(populate_from='title')
image = models.ImageField(
upload_to=upload_location,
null=True,
blank=True,
)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='postcategory')
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['-date_posted']
def __str__(self):
return self.title
def get_absolute_url(self, slug=None):
return reverse("posts-detail", kwargs={"slug": self.slug})
urls.py
from django.urls import path
from django.urls import path, include
from .views import PostView, PostDetailView,LatestPostView, CategoryPostListView
urlpatterns = [
path('', PostView.as_view(), name='posts-home'),
path('latest/', LatestPostView.as_view(), name='posts-latest'),
path('<slug>', PostDetailView.as_view(), name='posts-detail'),
path('category/<slug>', CategoryPostListView.as_view(), name='category-detail'),
]
views.py
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.shortcuts import redirect, render,get_object_or_404
#class based view
from django.views.generic import ListView, DetailView
from .models import Post, Category
class PostView(ListView):
template_name = 'posts/home.html'
model = Category
context_object_name = 'all_categs'
def get_queryset(self):
if self.request.user.is_authenticated:
return Category.objects.all()
else:
return Category.objects.all().exclude(title__iexact = 'Featured')[:6]
def get_context_data(self):
if not self.request.user.is_authenticated:
fcategory = Category.objects.get(title__iexact = 'Featured')
context = super(PostView, self).get_context_data()
context['latest_posts'] = Post.objects.exclude(category= fcategory).order_by('-date_posted')[0:6]
context['featured_posts'] = Post.objects.all().filter(category= fcategory).order_by('-date_posted')[0:6]
return context
else:
fcategory = Category.objects.get(title__iexact = 'Featured')
context = super(PostView, self).get_context_data()
context['latest_posts'] = Post.objects.order_by('-date_posted')
context['featured_posts'] = Post.objects.all().filter(category= fcategory).order_by('-date_posted')[0:6]
return context
# def get_success_url(self):
# return reverse('home') #add your path
class LatestPostView(LoginRequiredMixin, ListView):
template_name = 'posts/post_latest.html'
model = Post
context_object_name = 'Posts'
ordering = ['-date_posted']
paginate_by = 6
class PostDetailView(LoginRequiredMixin,DetailView):
model = Post
template_name = 'posts/post_detail.html'
class CategoryPostListView(LoginRequiredMixin, ListView):
model = Category
template_name = 'posts/category_detail.html'
# def get_queryset(self):
# category = get_object_or_404(Category, )
I thought of defining get_queryset inside CategoryPostListView. But I am not sure if it will work or not.
Firstly, if you are using ListView and want to display a list of posts, then you need model = Post.
Next, you can call get_object_or_404 in the get_queryset method. You can access slug from the URL with `self.kwargs['slug'].
Finally, you can filter the queryset to only return posts in that category.
class CategoryPostListView(LoginRequiredMixin, ListView):
model = Post
template_name = 'posts/category_detail.html'
def get_queryset(self):
category = get_object_or_404(Category, slug=self.kwargs['slug'])
return super(CategoryPostListView, self).get_queryset().filter(category=category)
Note that your problem is very similar to the dynamic filtering section in the docs.
Yes. you can use get_object_or_404 in class-based views. just add this to your CategoryPostListView:
class CategoryPostListView(LoginRequiredMixin, ListView):
model = Post
template_name = 'posts/category_detail.html'
def get_queryset(self):
category = get_object_or_404(Category, slug=self.kwargs['slug'])
# do another stuffs here
return Post.objects.filter(category=category)
for more information you can read dynamic filtering in class-based views in django official site
This is my views.py
from rest_framework import generics, permissions
from .models import Survey,Response
from .serialize import SurveySerializer,ResponseSerializer,SurveySerializerQuestion
from rest_framework.decorators import api_view
class SurveyList(generics.ListAPIView):
model = Survey
serializer_class = SurveySerializerQuestion
def get_queryset(self):
return Survey.objects.all()
class SurveyListByID(generics.ListAPIView):
model = Survey
serializer_class = SurveySerializer
def get_queryset(self):
survey_id = self.kwargs['survey_id']
return Survey.objects.filter(survey_id = survey_id)
class ResponseList(generics.ListAPIView):
model = Response
serializer_class = ResponseSerializer
def get_queryset(self):
survey_id = self.kwargs['survey_id']
return Response.objects.filter(survey_id = survey_id)
This is my urls.py
from django.conf.urls import patterns, include, url
from views import SurveyList,SurveyListByID,ResponseList
urlpatterns = patterns('',
url(r'^surveys/$', SurveyList.as_view(),name ='survey-list') ,
url(r'^surveys/(?P<survey_id>[0-9]+)/$', SurveyListByID.as_view(),name ='survey-list-by-id'),
url(r'^response/(?P<survey_id>[0-9]+)/$', ResponseList.as_view(),name ='response-list'),
)
This is serialize.py
from rest_framework import serializers
from .models import Employee,Survey,EmployeeSurvey,Response
class SurveySerializer(serializers.ModelSerializer):
class Meta:
model = Survey
fields = ('survey_id', 'question', 'choice1','choice2')
class SurveySerializerQuestion(serializers.ModelSerializer):
class Meta:
model = Survey
fields = ('survey_id', 'question')
class ResponseSerializer(serializers.ModelSerializer):
class Meta:
model = Response
fields = ('id','survey_id','choice1_count','choice2_count')
finally this is models.py
import re
from django.db import models
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
def alphanumeric_test(val):
if not re.match('^[0-9a-zA-Z]*$', val):
raise ValidationError('Only alphanumeric characters are allowed.')
def alphabetic_test(val):
if not re.match('^[a-zA-Z]*$', val):
raise ValidationError('Please enter alphabetic value.')
class Survey(models.Model):
survey_id = models.AutoField(primary_key=True)
question = models.CharField(max_length = 300)
choice1 = models.CharField(max_length = 100)
choice2 = models.CharField(max_length = 100)
def __unicode__(self):
return u'%s %s %s' % (self.question,self.choice1,self.choice2)
class Response(models.Model):
survey_id = models.ForeignKey(Survey, blank=True, null=True, on_delete=models.SET_NULL)
choice1_count = models.IntegerField()
choice2_count = models.IntegerField()
def __unicode__(self):
return u'%s %s %s' % (self.survey_id,self.choice1_count,self.choice2_count)
Now how do I write a POST request in Django Rest without UI and using the Django Rest Browser.
I want to do a POST request to capture the choice in the survey using a url like I did for get.Is that possible?
In views.py add a new class like this:
class SurveyAPIView(APIView):
def post(self, request, format=None):
serializer = SurveySerializer(request.data)
if serializer.is_valid():
instance = serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
and in urls.py add a new line like:
url(r'^create-survey/$', SurveyAPIView.as_view(),name ='create-survey') ,