Django rest framework serialization error - python

I have a django model that looks like this:
class AcademicProgramsManager(models.Manager):
def get_by_natural_key(self, acad_program_id, program_title, required_credits):
return self.get(acad_program_id = acad_program_id, program_title = program_title, required_credits = required_credits)
class AcademicPrograms(models.Model):
objects = AcademicProgramsManager()
acad_program_id = models.IntegerField(primary_key=True)
acad_program_category = models.ForeignKey(AcademicProgramCategories)
acad_program_type = models.ForeignKey(AcademicProgramTypes)
acad_program_code = models.CharField(max_length=25)
program_title = models.CharField(max_length=64)
required_credits = models.IntegerField()
min_gpa = models.FloatField()
description = models.CharField(max_length=1000)
def natural_key(self):
return (self.acad_program_id, self.program_title, self.required_credits)
class StudentAcademicPrograms(models.Model):
student = models.ForeignKey(Students)
academic_program = models.ForeignKey(AcademicPrograms)
credits_completed = models.IntegerField()
academic_program_gpa = models.FloatField()
primary_program = models.BooleanField()
This is my serializers.py file:
from studentapp.models import AcademicPrograms, AcademicProgramsManager, StudentAcademicPrograms
from rest_framework import serializers
class StudentAcademicProgramsSerializer(serializers.ModelSerializer):
class Meta:
model = StudentAcademicPrograms
fields = ('credits_completed','academic_program_gpa','primary_program')
class AcademicProgramsSerializer(serializers.ModelSerializer):
studentacademicprograms = StudentAcademicProgramsSerializer(many = True)
class Meta:
model = AcademicPrograms
fields = ('acad_program_id','program_title','required_credits','studentacademicprograms')
My api.py file looks like this:
from studentapp.models import AcademicPrograms, AcademicProgramsManager, StudentAcademicPrograms
from studentapp.serializers import StudentAcademicProgramsSerializer, AcademicProgramsSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
class AcademicProgramsList(APIView):
def get(self, request, format=None):
academicprograms = AcademicPrograms.objects.all()
serialized_academicprograms = AcademicProgramsSerializer(academicprograms, many=True)
return Response(serialized_academicprograms.data)
class AcademicProgramsDetail(APIView):
def get_onjects(self, pk):
try:
return AcademicPrograms.object.get(pk=pk)
except AcademicPrograms.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
academicprogram = self.get_object(pk)
serialized_academicprogram = AcademicProgramsSerializer(academicprogram)
return Response(serialized_academicprogram.data)
and finally my urls:
from django.conf.urls import patterns, include, url
from rest_framework.urlpatterns import format_suffix_patterns
from studentapp import api
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'texascompletes.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
#API:
url(r'^api/studentacademicprograms/$', api.AcademicProgramsList.as_view()),
url(r'^api/studentacademicprograms/(?P<pk>[0-9]+)/$', api.AcademicProgramsDetail.as_view()),
url(r'^admin/', include(admin.site.urls)),
)
urlpatterns = format_suffix_patterns(urlpatterns)
I am getting the following error when i give my api/studentacademicprograms
'AcademicPrograms' object has no attribute 'studentacademicprograms'
Where am i going wrong?

Try setting the source to the attribute/method name on the model. For example:
studentacademicprograms = StudentAcademicProgramsSerializer(
many=True,
source='studentacademicprograms_set')
The example given in the Django Rest Framework Serializer relations docs sets a related name on the models which matches the attribute name in the serializer (the default). If the names don't match you need to specify them model's source method/attribute to use.

Related

Filter for slug, title not working in Django rest Framework

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))

Django How to bring data into url from DB?

Models.py
from django.db import models
# Create your models here.
class reviewData(models.Model):
building_name = models.CharField(max_length=50)
review_content = models.TextField()
star_num = models.FloatField()
class buildingData(models.Model):
building_name = models.CharField(max_length=50)
building_loc = models.CharField(max_length=50)
building_call = models.CharField(max_length=20)
views.py
# Create your views here.
from django.shortcuts import render
from rest_framework.response import Response
from .models import reviewData
from .models import buildingData
from rest_framework.views import APIView
from .serializers import ReviewSerializer
class BuildingInfoAPI(APIView):
def get(request):
queryset = buildingData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
class ReviewListAPI(APIView):
def get(request):
queryset = reviewData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
urls.py
from django.contrib import admin
from django.urls import path
from crawling_data.views import ReviewListAPI
from crawling_data.views import BuildingInfoAPI
urlpatterns = [
path('admin/', admin.site.urls),
path('api/buildingdata/', BuildingInfoAPI.as_view()),
#path('api/buildingdata/(I want to put building name here)', ReviewListAPI.as_view())
]
I am making review api.
I want to use building name as url path to bring reviews for specific buildings
For example, there are a, b, c reviews
a, b reviews are for aaabuilding
c reviews are for xxxbuilding
api/buildingdata/aaabuilding (only shows aaabuilding review)
{
building_name = aaabuilding
review_content = a
star_num = 5
building_name = aaabuilding
review_content = b
star_num = 3
}
api/buildingdata/xxxbuilding (only shows xxxbuilding review)
{
building_name = xxxbuilding
review_content = c
star_num = 4
}
I've searched some dynamic url posts, but they were not that i want.
Is there any way to bring building name into url from db?
In urls.py
path('api/buildingdata/<str:building>/', BuildingInfoAPI.as_view()),
And in views.py
class BuildingInfoAPI(APIView):
def get(request, building):
queryset = buildingData.objects.filter(building_name__contains=building)
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
Hope this will solve the issue
I suggets you take a look at the django documentation, this is pretty well explained there, here is a useful link
In your urls.py, you should put:
from django.contrib import admin
from django.urls import path
from crawling_data.views import ReviewListAPI
from crawling_data.views import BuildingInfoAPI
urlpatterns = [
path('admin/', admin.site.urls),
path('api/buildingdata/', BuildingInfoAPI.as_view()),
# added <str:building> to url
path('api/buildingdata/<str:building>', ReviewListAPI.as_view())
]
And in your views.py:
# Create your views here.
from django.shortcuts import render
from rest_framework.response import Response
from .models import reviewData
from .models import buildingData
from rest_framework.views import APIView
from .serializers import ReviewSerializer
class BuildingInfoAPI(APIView):
def get(request):
queryset = buildingData.objects.all()
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)
class ReviewListAPI(APIView):
# added another argument, retrieved from url
def get(request, building):
# changed .all() to .filter()
queryset = reviewData.objects.filter(building_name = building)
serializer = ReviewSerializer(queryset, many=True)
return Response(serializer.data)

Django REST framework error - name is not defined

I have a Django 2.2 that has two apps - status and updates:
django_api
|
status
|
api
|
updates
In django_api/urls.py:
from django.contrib import admin
from django.urls import include, path
from updates.views import (
json_example_view,
JsonCBV,
JsonCBV2,
SerializedListView,
SerializedDetailView
)
from status.api.views import
StatusListSearchAPIView
urlpatterns = [
path('admin/', admin.site.urls),
path('api/status/', status.api.urls),
path('api/updates/', updates.api.urls),
In django_api/status/api/views.py:
from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import StatusSerializer
from status.models import Status
class StatusListSearchAPIView(APIView):
permission_classes = []
authentication_classes = []
def get(self, request, format = None):
qs = Status.objects.all()
serializer = StatusSeralizer(qs, many = True)
return Response(serializer.data)
def post(self, request, format=None):
qs = Status.objects.all()
serializer = StatusSeralizer(qs, many = True)
return Response(serializer.data)
class StatusAPIView(generics.ListAPIView):
permission_classes = []
authentication_classes = []
queryset = Status.objects.all()
serializer_class = StatusSeralizer
def get_queryset(self):
qs = Status.objects.all()
query = self.request.GET.get('q')
if query is not None:
qs = qs.filter(content_icontains = query)
return qs
In django_api/status/api/serializers.py:
from rest_framework import serializers
from django import forms
from status.models import Status
class StatusSerializer(serializers.ModelSerializer):
class Meta:
model = Status
fields = [
'user',
'content',
'image']
def validate_content(self, value):
if len(value) > 10000:
raise serializers.ValidationError("This is way too long.")
return value
def validate(self, data):
content = data.get("content", None)
if content == "":
content = None
image = data.get("image", None)
if content is None and image is None:
raise serializers.ValidationError("content or image is required.")
return data
When I run python manage.py runserver, I am getting an error:
File "...\status\api\views.py", line 26, in StatusAPIView
serializer_class = StatusSeralizer
NameError: name 'StatusSeralizer' is not defined
Updated: as indicated, this was a spelling error. However, after I imported status and from status.api imported urls, I am getting this error:
...\urls.py", line 39, in <module>
path('api/status/', status.api.urls),
...File "C:\Users\fbagi\AppData\Roaming\Python\Python37\site-
packages\django\urls\conf.py", line 73, in _path
raise TypeError('view must be a callable or a list/tuple in the case of
include().')
TypeError: view must be a callable or a list/tuple in the case of
include().
This is my status/api/urls.py:
from django.contrib import admin
from django.urls import path
from .views import StatusAPIView, StatusCreateAPIView
urlpatterns = [
path('/', StatusAPIView.as_view()),
path('create/', StatusCreateAPIView.as_view()),
]
Why am I getting this error?
It's a typo:
You are calling: StatusSeralizer but it is: StatusSerializer
I dont see StatusCreateAPIView in you views file. Have you created this view?
Try just commenting or removing path('create/', StatusCreateAPIView.as_view()), and see If you still get an error.
Try it bro:
from rest_framework import status.
Tell me if you have sucess!

django - Type Error __init__ positional argument

I'm creating a blog by django, when I want to open http://127.0.0.1:8000/accounts/login I get the error:
init() takes 1 positional argument but 2 were given
Exception Location:
C:\ProgramData\Miniconda3\envs\myDjanEnv\lib\site-packages\django\core\handlers\base.py
in _get_response, line 124
And this is the 124th line of the code from base.py:
if response is None:
wrapped_callback = self.make_view_atomic(callback)
try:
<!-- line 124 --> response = wrapped_callback(request, *callback_args, **callback_kwargs)
except Exception as e:
response = self.process_exception_by_middleware(e, request)
VIEWS.PY CODES:
from django.shortcuts import render,get_object_or_404,redirect
from django.utils import timezone
from blog.models import Post,Comment
from blog.forms import PostForm,CommentForm
from django.urls import reverse,reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.views.generic import (TemplateView,ListView,
DetailView,CreateView,
UpdateView,DeleteView,)
# Create your views here.
class AboutView(TemplateView):
template_name = 'about.html'
class PostListView(ListView):
model = Post
def get_queryset(self):
return Post.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
class PostDetailView(DetailView):
model = Post
class CreatePostView(LoginRequiredMixin,CreateView):
login_url = '/login/'
redirect_field_name = 'blog/post_detail.html'
# form_class = PostForm
model = Post
class PostUpdateView(LoginRequiredMixin,UpdateView):
login_url = '/login/'
redirect_field_name = 'blog/post_detail.html'
# form_class = PostForm
model = Post
class PostDeleteView(LoginRequiredMixin,DeleteView):
model = Post
success_url = reverse_lazy('post_list')
class DraftListView(LoginRequiredMixin,ListView):
login_url = '/login/'
redirect_field_name = 'blog/post_list.html'
model = Post
def get_queryset(self):
return Post.objects.filter(published_date__isnull=True,).order_by('created_date')
###############################################
###############################################
#login_required
def post_publish(request,pk):
post = get_object_or_404(Post,pk=pk)
post.publish
return redirect('post_detail',pk=pk)
#login_required
def add_comment_to_post(request,pk):
post = get_object_or_404(Post,pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail',pk=post.pk)
else:
form = CommentForm()
return render(request,'blog/comment_form.html',{'form':form})
#login_required
def comment_approve(request,pk):
comment = get_object_or_404(Comment,pk=pk)
comment.approve()
return redirect('post_detail',pk=comment.post.pk)
#login_required
def comment_remove(request,pk):
comment = get_object_or_404(Comment,pk=pk)
post_pk = comment.post.pk
comment.delete()
return redirect('post_detail',pk=post_pk)
FORMS.PY CODES:
from django import forms
from blog.models import Post,Comment
class PostForm(forms.ModelForm):
class Meta():
model = Post
fields = ('author','title','text')
widgets = {
'title':forms.TextInput(attrs={'class':'textinputclass'}),
'text':forms.Textarea(attrs={'class':'editable medium-editor-textarea postcontent'})
}
class CommentForm(forms.ModelForm):
class Meta():
model = Comment
fields = ('author','text')
widgets = {
'author':forms.TextInput(attrs={'class':'textinputclass'}),
'text':forms.Textarea(attrs={'class':'editable medium-editor-textarea'})
}
MODELS.PY CODES:
from django.db import models
from django.utils import timezone
from django.urls import reverse,reverse_lazy
# Create your models here.
class Post(models.Model):
author = models.ForeignKey('auth.User',on_delete=models.PROTECT)
title = models.CharField(max_length=200)
text = models.TextField()
create_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True,null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def approve_comments(self):
return self.comments.filter(approve_comment=True)
def get_absolute_rul(self):
return reverse("post_detail",kwargs={'pk':self.pk})
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey('blog.Post',related_name='comments',on_delete=models.PROTECT)
author = models.CharField(max_length=200)
text = models.TextField()
create_date = models.DateTimeField(default=timezone.now)
approve_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def get_absolute_rul(self):
return reverse('post_list')
def __str__(self):
return self.text
URLS.PY (in the same folder that setting.py is in):
from django.contrib import admin
from django.urls import path
from django.conf.urls import url,include
from django.contrib.auth import views
from django.contrib.auth.views import LoginView
urlpatterns = [
path('admin/', admin.site.urls),
url(r'',include('blog.urls')),
url(r'accounts/login/$',views.LoginView,name='login'),
url(r'accounts/logout/$',views.LogoutView,name='logout',kwargs={'next_page':'/'}),
]
URLS.PY (in the same folder that VIEWS.PY is in)
from django.conf.urls import url
from blog import views
urlpatterns = [
url(r'^$',views.PostListView.as_view(),name='post_list'),
url(r'^about/$',views.AboutView.as_view(),name='about'),
url(r'^post/(?P<pk>\d+)$',views.PostDetailView.as_view(),name='post_detail'),
url(r'^post/new/$',views.CreatePostView.as_view(),name='post_new'),
url(r'^post/(?P<pk>\d+)/edit/$',views.PostUpdateView.as_view(),name='post_edit'),
url(r'^post/(?P<pk>\d+)/remove/$',views.PostDetailView.as_view(),name='post_remove'),
url(r'^drafts/$',views.DraftListView.as_view(),name='post_draft_list'),
url(r'^post/(?P<pk>\d+)/comment/$',views.add_comment_to_post,name='add_comment_to_post'),
url(r'^post/(?P<pk>\d+)/approve/$',views.comment_approve,name='comment_approve'),
url(r'^post/(?P<pk>\d+)/remove/$',views.comment_remove,name='comment_remove'),
url(r'^post/(?P<pk>\d+)/publish/$',views.post_publish,name='post_publish'),
]
What is the problem?
In your urls, you are not using as_view() at the end of class based views. You need to use it like this:
path('about/', AboutView.as_view(), name='about')
Update
Problem is in your LoginView and LogoutView which is imported from django.contrib.auth.views. They are class Based Views. So you need to add as_view at the end of them when declaring in the class.
url(r'accounts/login/$',views.LoginView.as_view(),name='login'),
url(r'accounts/logout/$',views.LogoutView.as_view(),name='logout',kwargs={'next_page':'/'})

Post Request Django REST Framework

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') ,

Categories

Resources