error messages
ValueError: Cannot assign "<User: user0#example.com>": "Diagnoses.owner" must be a "Patient" instance
i get the above error when i try to create either a new card or diagnoses.
The card and diagnoses are meant to be an instance of the patient, just like the way a patient has a card and also diagnoses. The patient class has a foregin key referencing the User.
Here is the code
views.py
from django.shortcuts import render
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from .serializers import PatientsSerializer, PatientsCardSerializer, PatientsDiagnosesSerializer
from .models import Patient, Card, Diagnoses
from rest_framework import permissions
from .permissions import IsOwner
# Patient Views
class PatientListAPIView(ListCreateAPIView):
serializer_class = PatientsSerializer
queryset = Patient.objects.all()
permission_classes = (permissions.IsAuthenticated, IsOwner,)
def perform_create(self, serializer):
return serializer.save(owner=self.request.user)
def get_queryset(self):
return self.queryset.filter(owner=self.request.user)
class PatientDetailAPIView(RetrieveUpdateDestroyAPIView):
serializer_class = PatientsSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner,)
queryset = Patient.objects.all()
lookup_field = "id"
def get_queryset(self):
return self.queryset.filter(owner=self.request.user)
class PatientCardListAPIView(ListCreateAPIView):
serializer_class = PatientsCardSerializer
queryset = Card.objects.all()
permission_classes = (permissions.IsAuthenticated,)
def perform_create(self, serializer):
return serializer.save(owner=self.request.user)
def get_queryset(self):
return self.queryset.filter(owner=self.request.user)
class PatientCardDetailAPIView(RetrieveUpdateDestroyAPIView):
serializer_class = PatientsCardSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner,)
queryset = Card.objects.all()
lookup_field = "id"
def get_queryset(self):
return self.queryset.filter(owner=self.request.user)
class PatientDiagnosesListAPIView(ListCreateAPIView):
serializer_class = PatientsDiagnosesSerializer
queryset = Diagnoses.objects.all()
permission_classes = (permissions.IsAuthenticated,)
def perform_create(self, serializer):
return serializer.save(owner=self.request.user)
def get_queryset(self):
return self.queryset.filter(owner=self.request.user)
class PatientDiagnosesDetailAPIView(RetrieveUpdateDestroyAPIView):
serializer_class = PatientsDiagnosesSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner,)
queryset = Diagnoses.objects.all()
lookup_field = "id"
def get_queryset(self):
return self.queryset.filter(owner=self.request.user)
Models.py
class Patient(models.Model):
name = models.CharField(max_length=255, null=True)
country = models.CharField(max_length=255, null=True)
state = models.CharField(max_length=255, null=True)
phone = models.CharField(max_length=255, null=True)
email = models.CharField(max_length=255, null=True)
owner = models.ForeignKey(to=User, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Card(models.Model):
name = models.CharField(max_length=255, null=True)
card_number = models.CharField(max_length=255, null=True)
owner = models.OneToOneField(Patient, null=True, blank=True, on_delete=models.CASCADE)
def __str__(self):
return (self.patient.name)+"'s card"
class Diagnoses(models.Model):
sickness = models.CharField(max_length=255, null=True)
note = models.TextField(max_length=255, null=True)
owner = models.ForeignKey(Patient, null=True, on_delete=models.SET_NULL)
def __str__(self):
return (self.patient.name)+"'s diagnoses"
So far, self.request.user is a User Object. You cannot save it to the API or save to the model because of that. And for clarity, it's not a Patient Object.
Based on your situation, I would queue the Patient object with the User object (if this was a one-way reference object), and put that in the argument and do the save() method.
class PatientCardListAPIView(ListCreateAPIView):
serializer_class = PatientsCardSerializer
queryset = Card.objects.all()
permission_classes = (permissions.IsAuthenticated,)
def perform_create(self, serializer):
getPatientFromUser = Patient.objects.get(owner=self.request.user)
# getPatientFromUser returns `Patient` Instance. So you could bind it in `Card` Model.
return serializer.save(owner=getPatientFromUser)
def get_queryset(self):
return self.queryset.filter(owner=self.request.user)
Notes:
This is a solution for a one-way reference. (User being referred to as Patient)
If you have a cross-reference relationship between User and Patience (where User and Patience has a ForeignKey on each other), then declare your User Model.
The solution queries the Patient from User. As User is incompatible with that Foreign Object.
Related
I don't know why I have this error, I didn't have it befor, I'm sure that I'm logged in before trying call the api, please find below the code :
views.py
class AlbumCreate(generics.CreateAPIView):
serializer_class = AlbumsSerializer
def perform_create(self, serializer):
owner2 = self.request.user
serializer.save(owner=owner2)
class AlbumList(generics.ListAPIView):
permission_classes = [IsAuthenticated]
queryset = Album.objects.all()
serializer_class = AlbumsSerializer
class AlbumDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Album.objects.all()
serializer_class = AlbumsSerializer
Serializer
class AlbumsSerializer(serializers.ModelSerializer):
owner = serializers.StringRelatedField(read_only=True)
class Meta:
model = Album
fields = "__all__"
models
def upload_path(instance, filname):
return '/'.join(['covers', str(instance.title), filname])
class Album(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=30)
cover = models.IntegerField(default=0)
photos_number = models.IntegerField(default=0)
image = models.ImageField(blank=True, null=True, upload_to=upload_path)
def __str__(self):
return self.title
I am using djangorestframework==3.12.1 Here is how my code looks like:-
models.py
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=14, decimal_places=2)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
class Meta:
unique_together = (
("name", "user"),
)
serializers.py
class ProductSerializer(serializers.ModelSerializer):
"""serializer for Product objects."""
class Meta:
model = models.Product
fields = '__all__'
read_only_fields = ['user',]
views.py
class ProductViewset(viewsets.ModelViewSet):
queryset = models.Product.objects.all()
permission_classes = [permissions.IsAuthenticated]
serializer_class = serializers.ProductSerializer
Expected Behavior
The validators on the Modelserializers must raise an exception as Product with this Name and User already exists.
Actual Behavior
IntegrityError at /api/v1/product/ UNIQUE constraint failed: projectapp_product.name, projectapp_product.user_id
How do I fix this?
You can try to override the perform_create of ProductViewSet
like this:
class ProductViewset(viewsets.ModelViewSet):
queryset = models.Product.objects.all()
permission_classes = [permissions.IsAuthenticated]
serializer_class = serializers.ProductSerializer
def perform_create(self, serializer):
user = self.request.user
try:
serializer.save(user=user)
except IntegrityError:
raise ValidationError('Product with this Name and User already exists.')
I am following a course on DRF. It basically is creating a Q&A site. Now I tried answering a Question using the DRF interface.
But when I look at the question, it still shows answer count as zero.
But the answwers are visible on the Django Admin Panel.
My code for the same is:
models.py file
class Question(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
content = models.CharField(max_length=240)
slug = models.SlugField(max_length=240, unique=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="questions")
def __str__(self):
return self.content
class Answer(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
body = models.TextField()
question = models.ForeignKey(Question,
on_delete=models.CASCADE,
related_name="answers", null=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
voters = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='votes')
def __str__(self):
return f'{self.body} by {self.author.username}'
The serializers.py file:
from rest_framework import serializers
from ..models import (Answer, Question)
class AnswerSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField(read_only=True)
created_at = serializers.SerializerMethodField(read_only=True)
likes_count = serializers.SerializerMethodField(read_only=True)
user_has_voted = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Answer
exclude = ['question', 'voters', 'updated_at']
def get_created_at(self, instance):
return instance.created_at.strftime("%B %d %y")
def get_likes_count(self, instance):
return instance.voters.count()
def get_user_has_voted(self, instance):
request = self.context.get('request')
return instance.voters.filter(pk=request.user.pk).exists()
class QuestionSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField(read_only=True)
created_at = serializers.SerializerMethodField(read_only=True)
slug = serializers.SlugField(read_only=True)
answers_count = serializers.SerializerMethodField(read_only=True)
user_has_answered = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Question
exclude = ['updated_at']
def get_created_at(self, instance):
return instance.created_at.strftime("%B %d %y")
def get_answers_count(self, instance):
return instance.answers.count()
def get_user_has_answered(self, instance):
request = self.context.get('request')
return instance.answers.filter(author=request.user.pk).exists()
And the views.py file
from rest_framework import generics, viewsets
from rest_framework.generics import get_object_or_404
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from ..models import Question, Answer
from .serializers import QuestionSerializer, AnswerSerializer
from .permissions import IsAuthorOrReadOnly
class QuestionViewSet(viewsets.ModelViewSet):
queryset = Question.objects.all()
lookup_field = 'slug'
serializer_class = QuestionSerializer
permissions_class = [IsAuthorOrReadOnly, IsAuthenticated]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
class AnswerCreateAPIView(generics.CreateAPIView):
queryset = Answer.objects.all()
serializer_class = AnswerSerializer
permission_classes = [IsAuthenticated]
def perform_create(self, serializer):
request_user = self.request.user
kwarg_slug = self.kwargs.get("slug")
question = get_object_or_404(Question, slug=kwarg_slug)
if question.answers.filter(author=request_user).exists():
raise ValidationError('You Have Already Answered')
serializer.save(author=self.request.user)
You need provide question for the creation of answer explicitly if you exlcude product in your AnswerSerializer
class AnswerCreateAPIView(generics.CreateAPIView):
...
def perform_create(self, serializer):
...
serializer.save(author=self.request.user, question=question)
I have several ViewSets.They have one serializer and model.
For example - ViewSet "Posts" and "Favorites". If I use DELETE request on Post object, he is deleted from "Posts", but in Favorites, I can see them. BUT, every object has a "URL" field. So, if some object from "Posts" will be deleted, then in "Favorites" I will see it and if I go to the link from the "URL" field, then I get "404 not found".
Why does it happen?
Model:
class Post(models.Model):
name = models.CharField(verbose_name='name', db_index=True, max_length=64)
city = models.CharField(verbose_name='city', db_index=True, max_length=64)
created = models.DateTimeField(auto_now_add=True)
end_time = models.DateTimeField(default=next_month, blank=True, editable=False)
description = models.CharField(verbose_name='description', db_index=True, max_length=64)
isFan = models.BooleanField(null=True)
main_image = models.ImageField(upload_to=get_auth_dir_path, null=True, max_length=255)
first_image = models.ImageField(upload_to=get_auth_dir_path, null=True, max_length=255)
second_image = models.ImageField(upload_to=get_auth_dir_path, null=True, max_length=255)
ViewSets:
class PostViewSet(LikedMixin, viewsets.ModelViewSet):
queryset = Post.objects.is_actual().order_by('-created')
serializer_class = PostSerializer
authentication_classes = (TokenAuthentication, SessionAuthentication, )
filter_backends = (DjangoFilterBackend, )
filterset_fields = (...)
def perform_create(self, serializer):
serializer.save(author=self.request.user)
class ClosedPostViewSet(LikedMixin, viewsets.ModelViewSet):
queryset = Post.objects.is_not_actual().order_by('-end_time')
serializer_class = PostSerializer
authentication_classes = (TokenAuthentication, SessionAuthentication,)
filter_backends = (DjangoFilterBackend,)
filterset_fields = (...)
def perform_create(self, serializer):
serializer.save(author=self.request.user)
class SearchViewSet(LikedMixin, viewsets.ModelViewSet):
pagination_class = None
queryset = Post.objects.is_actual()
serializer_class = PostSerializer
authentication_classes = (TokenAuthentication, SessionAuthentication, )
filter_backends = (DjangoFilterBackend, )
filterset_fields = (...)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
result_list = list(queryset.values('city').annotate(count=Count('city')))
return Response(result_list)
def perform_create(self, serializer):
serializer.save(author=self.request.user)
I have been trying to use the Django_filter on an APIView, but it just does not work. I am trying to implement a filter search, on some fields on a model.
below is how the model is set up
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
name = models.CharField(max_length=250)
picture = models.TextField(null=True, blank=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(max_length=255, unique=True, blank=True)
class Skill(models.Model):
name = models.CharField(max_length=60)
subcategory = models.CharField(max_length=60, blank=True, null=True)
created_on = models.DateTimeField(auto_now=True)
updated_on = models.DateTimeField(auto_now_add=True)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.DO_NOTHING)
the views.py set up is also as shown below
from django_filters import rest_framework as filters
class UserFilter(filters.FilterSet):
email = filters.CharFilter(lookup_expr='icontains')
name = filters.CharFilter(lookup_expr='icontains')
profiles__skills = filters.CharFilter(lookup_expr='icontains')
class Meta:
model = User
fields = ('email', 'name', 'profiles__skills')
class ListUsersView(APIView, MyPaginationMixin):
'''
Gets all the users in the database
'''
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [AllowAny]
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
filterset_class = UserFilter
def get(self, request):
page = self.paginate_queryset(self.queryset)
if page is not None:
serializer_context = {"request": request}
serializer = self.serializer_class(page, context=serializer_context, many=True)
return self.get_paginated_response(serializer.data)
and finally my serializer.py
class UserSerializer(serializers.ModelSerializer):
slug = serializers.SlugField(read_only=True)
class Meta:
model = User
fields = ('email', 'name', 'slug', 'picture')
read_only_fields = ('email', 'name', 'slug',)
my urls.py
path('users/', qv.ListUsersView.as_view(), name='list-users'),
this is how my result looks like
please, how can I get the Django filter to work on the APIView
It seems you are trying to get the similar or exact behavior of DRF ListAPIView by using APIView. I would suggest using ListAPIView over APIView in your case.
from rest_framework import generics
from django_filters import rest_framework as filters
class ListUsersView(generics.ListAPIView):
'''
Gets all the users in the database
'''
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [AllowAny]
filterset_class = UserFilter
filter_backends = (filters.backends.DjangoFilterBackend,)
To add filtering capability in APIView,
class MyAPIViewKlass(APIView):
filter_backends = (filters.DjangoFilterBackend,)
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
def get(self, request, *args, **kwargs):
base_qs = MyModel.objects.all()
filtered_qs = self.filter_queryset(base_qs)
serializer = MySerializer(filtered_qs, many=True)
return Response(serializer.data)