I am gettting this error although I am giving proper string in Text and Title fields.I don't know what are the reasons,However i am able to post the values of remaining three fields(author,Created_date,publish_date).
Serializer.py
from rest_framework import serializers
from blog.models import Post
from django.utils import timezone
from rest_framework.validators import UniqueValidator
class blogSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('author','title', 'text','created_date','published_date')
model.py
from django.db import models
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey('auth.User',null=True)
title = models.CharField(max_length=200)
text = models.CharField(max_length=200)
created_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 __str__(self):
return self.title
views.py
from blog.models import Post
from .serializers import UserSerializer, GroupSerializer,blogSerializer
from rest_framework import viewsets,status
from rest_framework.decorators import api_view
class blogViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = blogSerializer
here i am posting the data.
#api_view(['GET', 'POST'])
def blog_list(request):
if request.method=='GET':
my_blog=Post.objects.all()
serializers=blogSerializer(my_blog,Many=True)
return JsoResponse(serializers.data,safe=False)
elif request.method=='POST':
data=JSONParser().parse(request)
serializers=blogSerializer(data=data)
if serializers.is_valid():
serializer.save()
return JsonResponse(serializers.data,status=201)
return JsonResponse(serializers.errors,status=400)
I would set up a unit test to test this functionality. It looks like none of your post data is getting to the serializer otherwise the valid fields would have been repopulated once you submit the form and the for is returned with errors. The title and text fields are also the only fields which are required/do not have a default value.
If you are using some form of decorator(or something similar) on the view which accesses request.data, this might be what is causing the issue. Since rest framework modifies request.POST when populating request.data
Related
In my Django rest framework project I want to make sure that for example if testuser1 is logged in when posting a post cannot on the author part chose testuser2 and post the post with the author being testuser2. How I can I make sure only the logged in user creates a post?
my models.py
from turtle import title
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
body = models.TextField()
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
my views.py
from django.shortcuts import render
from rest_framework import generics, permissions
from .models import Post
from .serializers import PostSerializer
from .permissions import IsAuthorOrReadOnly
class PostList(generics.ListCreateAPIView):
#permission_classes = (permissions.IsAuthenticated,)
queryset = Post.objects.all()
serializer_class = PostSerializer
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (IsAuthorOrReadOnly,)
queryset = Post.objects.all()
serializer_class = PostSerializer
my serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
fields = ('id', 'author', 'title', 'body', 'created_at',)
model = Post
my permissions.py
from re import T
from tkinter.tix import Tree
from rest_framework import permissions
class IsAuthorOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# Read-only permissions are allowed for any request
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the author of a post
return obj.author == request.user
use perform_create worked for me
def perform_create(self, serializer):
serializer.save(author = self.request.user)
I am designing Basic Django rest framework based application, i need to compare external parameters passed through POST method in Postman with Coupon code in database and generate custom response like 'This code is redeemed/validate." or " This is invalid coupon/code."
Here is my Model.py file :
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
class Coupon(models.Model):
code = models.CharField(max_length=50, unique=True)
valid_from = models.DateTimeField()
valid_to = models.DateTimeField()
discount = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(100)])
active = models.BooleanField()
def __str__(self):
return self.code
here is my views.py file:
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Coupon
from .serializers import CouponSerializer
from rest_framework import viewsets
class CouponViewSet(viewsets.ModelViewSet):
queryset = Coupon.objects.all()
serializer_class = CouponSerializer
#api_view(['POST'])
def coupon_redeem(request):
if request.method =='POST':
serializer = CouponSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
here is my Serializer.py file
from rest_framework import serializers
from .models import Coupon
class CouponSerializer(serializers.ModelSerializer):
class Meta:
model = Coupon
fields = '__all__'
Please help if possible, Thank you.
IN Your post method u can filter the desired object like:
if serializer.is_valid():
coup=Coupon.objects.filter(code=serializer.data['code'],active=True).exists()
if(coup=="NULL"):
return Response("This is invalid coupon/code",status=status.HTTP_400_BAD_REQUEST)
else:
return Response("This is valid code",status=status.HTTP_200_OK)
So I am building a to do app in Django. I have created databases for the users and todo items. But I have a problem, how can each user have its own data. Like every user should add their own data. It seems like there is no answer out there.
My models.py
class Task(models.Model):
title = models.CharField(max_length=200)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
My forms.py
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username','email','password1','password2']
So how can I connect those both. I have red that I have to use foreign key. But I really don't understand how I can do it
You specify a ForeignKey [Django-doc] in the Task model that refers to the user that constructed it:
# app/models.py
from django.db import models
from django.conf import settings
class Task(models.Model):
title = models.CharField(max_length=200)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
return self.title
You can then make a ModelForm where you exclude the user. For example:
# app/forms.py
from django import forms
from app.models import Task
class TaskForm(forms.ModelForm):
class Meta:
model = Task
exclude = ['user']
Then in the view we can "inject" the user in the instance we create, for example:
# app/views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
from app.forms import TaskForm
#login_required
def create_task(request):
if request.method == 'POST':
form = TaskForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('name-of-some-view')
else:
form = TaskForm()
return render(request, 'some_template.html', {'form': form})
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
I am new to django. In my project I want to make home page which views some of the post.But if user get registered or authenticated then they can view all the post available on the website. so far I have created the view which renders all the post on home page but I want to limit them.
I am using class based view.
posts/views.py
from django.views.generic import ListView, DetailView
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'posts/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
class PostDetailView(DetailView):
model = Post
template_name = 'posts/post_detail.html'
posts/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)
def __unicode__(self):
return self.title
def __str__(self):
return self.title
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)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts-detail", kwargs={"pk": self.pk})
In a ListView, the default QuerySet is all objects. In your case, with the model set to Post, the default queryset is Post.objects.all().
You can override the get_queryset() method of the ListView. Check out this website to get a good understanding of Django CBVs.
def get_queryset(self):
qs = super().get_queryset()
if self.request.user.is_authenticated:
return qs
else:
return qs.filter(<add a filter for not logged in users>)
# of return qs[:10] # to limit to 10 posts
Redirecting the user
You can use the LoginRequiredMixin [Django-doc] to prevent users to see a view if they are not logged in. In that case the default behavior is to redirect to the login page.
You can add the mixin to your views like:
# posts/views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView, DetailView
from .models import Post
class PostListView(LoginRequiredMixin, ListView):
model = Post
template_name = 'posts/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
class PostDetailView(LoginRequiredMixin, DetailView):
model = Post
template_name = 'posts/post_detail.html'
The documentation describes that you can set the redirect_to class attribute to something else if you want to redirect the user to another page.
Show a page without Posts (or filter these)
You can also decide to render the page, but without any Post objects. We can handle that by patching the get_queryset method:
# posts/views.py
from django.views.generic import ListView, DetailView
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'posts/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
def get_queryset(self):
if not self.request.user.is_authenticated:
return Post.objects.none()
else:
return super().get_queryset()
class PostDetailView(DetailView):
model = Post
template_name = 'posts/post_detail.html'
def get_queryset(self):
if not self.request.user.is_authenticated:
return Post.objects.none()
else:
return super().get_queryset()
I have a model, and I just want to show the data of the model in my /api/
from django.db import models
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
class Book(models.Model):
order_id = models.IntegerField()
isbn = models.IntegerField()
publisher = models.CharField(max_length=256)
school = models.CharField(max_length=256)
price = models.IntegerField()
duration = models.CharField(max_length=10)
order_datetime = models.DateTimeField(auto_now=False, auto_now_add=False)
def __str__(self):
return str(self.order_id)
This is my urls.py:
from django.contrib import admin
from django.urls import path
from filter import views
urlpatterns = [
path('', views.index, name='index'),
path('api/', views.BookApiView.as_view(), name='book_api'),
path('admin/', admin.site.urls),
]
This is my views.py:
from django.shortcuts import render
from rest_framework.views import APIView
from .models import Book
from django.http import JsonResponse
class BookApiView(APIView):
def get(self, request, format=None):
books = Book.objects.all()
return JsonResponse({'model': list(books)})
I get the following error: 'Object of type 'Book' is not JSON serializable'
Regards,
Anthony
Django models can't be JSON serialized implicitly.
You need a serializer to convert the model into a representation that is JSON serializable (primitive dicts, lists, numbers, strings, etc)
Django rest framework serializer docs: http://www.django-rest-framework.org/api-guide/serializers/
class BookSerializer(serializers.Serializer):
order_id = serializers.IntegerField()
isbn = serializers.CharField()
...
class BookApiView(APIView):
def get(self, request, format=None):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return JsonResponse({'model': serializer.data})
Man... You need a 'Serializer' before send the data to the view!
The Serializez class get the abstract data from the django ORM and parse the data easily to JSON.
Create a file serializers.py at the same level of view.py
and:
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
After you create the SerializerBook class, import this on your view and pass the book queryset as the first parameter of the BookSerializer.
...
class BookApiView(APIView):
def get(self, request, format=None):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
You should define serializer to convert the model instance data to respective JSON data, So define a serializer.py as below
class BookSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = Book
then in your view, change as below,<br>
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
class BookApiView(APIView):
def get(self, request, format=None):
booksqueryset = Book.objects.all()
serializer = BookSerializer(booksqueryset, many=True)
return Response(data=serializer.data)
Read this DRF ModelSerializer Official Doc for more details