Django rest framework Detail not found while deleting - django

i have a a problem deleting an object via API. So i have 2 models, Answer and Vote vote is connected to Answer via foreignKey like this
class Vote(models.Model):
class AnswerScore(models.IntegerChoices):
add = 1
subtract = -1
score = models.IntegerField(choices=AnswerScore.choices)
answer = models.ForeignKey('Answer', on_delete=models.PROTECT)
user = models.ForeignKey('users.CustomUser', on_delete=models.PROTECT)
class Meta:
unique_together = ('answer', 'user',)
class Answer(models.Model):
answer = models.TextField()
created_at = models.DateTimeField(editable=False, default=timezone.now)
updated_at = models.DateTimeField(default=timezone.now)
user = models.ForeignKey('users.CustomUser', on_delete=models.PROTECT)
question = models.ForeignKey('Question', on_delete=models.PROTECT)
number_of_points = models.IntegerField(default=0)
moderate_status = models.BooleanField(default=False)
Now i have an API endpoint for creating a Vote for user on a particular answer
path('answers/<int:pk>/vote', VoteCreate.as_view()),
Looks like this:
class VoteSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
answer = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Vote
fields = '__all__'
class VoteCreate(ParentKeyAPIView, generics.CreateAPIView):
model = Vote
parent_model_field = 'answer_id'
serializer_class = VoteSerializer
def perform_create_kwargs(self, **kwargs):
answer_id = self.kwargs['pk']
answer = Answer.objects.get(id=int(answer_id))
if Vote.objects.filter(user=self.request.user, answer=answer).exists():
old_vote = Vote.objects.get(user=self.request.user, answer=answer)
answer -= old_vote.score
answer.save()
old_vote.delete()
return super().perform_create_kwargs(user=self.request.user, answer_id=answer_id, **kwargs)
Im using the same serializer just like above*
I get an error:
Not Found: /api/v1/answers/55/voteDelete
There is no any traceback, i have checked in fact that in database the Vote with answer_id 55 exists and i can delete them via django-admin but cant via API.
Do you have any idea why?

First thing - let's change get_queryset to get_object, because you want single object. Then instead of answer_id=self.kwargs['pk'] simplify it to answer=self.kwargs['pk'].
Another thing - I think it's might be better to delete old vote while creating new one. You don't need serializer or special view for that. Just add to function creating new Vote object in your view:
class VoteCreate(...):
...
def perform_create_kwargs(self, **kwargs):
answer_id = self.kwargs['pk']
answer = Answer.object.get(id=int(answer_id))
if Vote.objects.filter(user=self.request.user, answer=answer).exists():
old_vote = Vote.objects.get(user=self.request.user, answer=answer)
answer.number_of_points -= old_vote.score
answer.save()
old_vote.delete()
return super().perform_create_kwargs(user=self.request.user, answer_id=answer_id, **kwargs)

Related

How to retrieve data from model that current user created and list it for another model's field in django

Let us imagine that I have two models.
First model contains curse details and user that created this course
class Course(models.Model):
course_name = models.CharField(max_length=100, null=False)
description = models.CharField(max_length=255)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
and my second model is:
class Lesson(models.Model):
course = models.OneToOneField(Course, on_delete=models.CASCADE) #
# inside the course I want my APIVIEW to list only the courses that current user created.
# OnetoOne relationship does not solve the problem.
status = models.CharField(choices=STATUS, null=False, default=GOZLEMEDE,max_length=20)
tariffs = models.FloatField(max_length=5,null=False,default=0.00)
continues_off = models.CharField(max_length=2)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
My serializers for both Models:
class LessonSerializer(serializers.ModelSerializer):
class Meta:
model = models.Lesson
fields = ('course', 'status', 'tariffs', 'continues_off', 'user_profile')
def create(self, validated_data):
lesson = models.Lesson.objects.create(
course = validated_data['course'],
status = validated_data['status'],
tariffs=validated_data['tariffs'],
continues_off=validated_data['continues_off'],
user_profile=validated_data['user_profile']
)
return lesson
class CourseSerializer(serializers.ModelSerializer):
"""Serializers Course content"""
class Meta:
model = models.Course
fields = '__all__'
def create(self,validated_data):
course = models.Course.objects.create(
course_name = validated_data['course_name'],
description=validated_data['description'],
user_profile=validated_data['user_profile']
)
return course
My Viewset:
class LessonViewset(viewsets.ModelViewSet):
model = models.Lesson
serializer_class = serializers.LessonSerializer
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,BasePermission,)
def get_queryset(self):
user_current = self.request.user.id
return models.Lesson.objects.filter(user_profile=user_current)
How can I get the desired result. I want to get the courses for the current user and show them as a dropdown list in my API view. Just only the courses that user created should be in the dropdown list not all.
OnetoOne relationship gives all results of course table.
i think change your view code to :
def get_queryset(self,id):
return model.objects.filter(user_profile=id)
#You do not need to call it again when you put the Lesson on the model
\

How to save multiple django form in one page with one submit button

i'm new when developing django. I have some question after days by days finding the answer. Here the go.
What i want is making ajax form that handle 2 model form, with 1 submit button
I can already saved the data in each form, but got problem in foreign key field got None instead
Here we go my model:
class ModelA(models.Model):
name = models.CharField(max_length=100, blank=True)
info = models.CharField(max_length=200, blank=True)
def __str__(self):
return self.name
class ModelB(models.Model):
xmodel = models.ForeignKey(to=ModelA, on_delete=models.CASCADE, related_name='modelX', blank=True, null=True)
no_1 = models.CharField(max_length=150, blank=True)
no_2 = models.CharField(max_length=150, blank=True)
Form Class:
class ModelAForm(forms.ModelForm):
class Meta:
model = ModelA
fields = '__all__'
class ModelBForm(forms.ModelForm):
class Meta:
model = ModelB
exclude = ('xmodel',)
View class:
def AddData(request):
tpl = 'add.html'
if request.method == 'POST':
mdla = ModelAForm(request.POST)
mdlb = ModelBForm(request.POST)
if mdla.is_valid():
obj = mdla.save()
if mdlb.is_valid():
mdlb.save(commit=False)
mdlb.xmodel=obj
mdlb.save()
else:
mdla = ModelAForm()
mdlb = ModelbForm()
In TPL i'm using ajax to send, it can save model a and model b, but in modelb xmodel (foreign key) it got None when check in adminpanel.
Which i do wrong, how to make it happen when handling the forms?
For people that got something like me, using 2 form.
i've solved my problem with this logic.
Create object manually
Initiatite form with instance new object
save
for above problem:
def AddData(request):
tpl = 'add.html'
if request.method == 'POST':
mdla = ModelAForm(request.POST)
if mdla.is_valid():
obj = mdla.save()
newObj = ModelB.objects.create(xmodel=obj)
mdlb = ModelBForm(request.POST, instance=newObj)
if mdlb.is_valid():
mdlb.save()
else:
mdla = ModalAForm()
mdlb = ModalBForm
This is solution i get, if anyone could do better please tell me. Thankx

How to run two methods inside django models in parallel manner?

I'm incrementing two different fields in User models which are the number of likes given to user's post and number of likes received by the user's post. I did this through adding two methods in class model. It is working when I'm liking other posts but however, if I liked my own post it is not working. Anyone know how to solve this problem?
Code snippet for user models
class User(models.Model):
username = models.CharField(max_length=100)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField(null=True)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
datetime_joined = models.DateTimeField(auto_now_add=True)
num_likes_received = models.IntegerField(default=0)
num_dislikes_received = models.IntegerField(default=0)
num_likes_given = models.IntegerField(default=0)
num_dislikes_given = models.IntegerField(default=0)
total_votes = models.IntegerField(default=0)
prediction = models.BooleanField(default=True)
def add_total_votes(self, vote):
self.total_votes += vote
self.save()
def inc_num_likes_received(self):
self.num_likes_received += 1
print("1 like received")
self.save()
def inc_num_likes_given(self):
self.num_likes_given += 1
print("1 like given")
self.save()
Code snippet for Post Model
class Post(models.Model):
post = models.TextField()
num_likes = models.IntegerField(default=0)
num_dislikes = models.IntegerField(default=0)
username = models.ForeignKey(User, on_delete=models.CASCADE)
datetime_comments = models.DateTimeField(auto_now_add=True)
def add_num_likes(self):
self.num_likes+=1
self.save()
def __str__(self):
return str(self.id)
Function for submitting like to certain post and at the same time this is where I executed the created two method from the models. (inc_num_likes_received and inc_num_likes_given)
def submit_like(request):
User_PK = User.objects.get(username=request.user)
User_Give_Like = get_object_or_404(User, pk=User_PK.id)
pk = request.POST.get('Status', None)
post = get_object_or_404(Post, pk=pk)
post.add_num_likes()
User_PK_Receive = User.objects.get(id=post.username.id)
User_Receive_Like = get_object_or_404(User, pk=User_PK_Receive.id)
LikeObject = Likes(username = User_Give_Like, post = post, liked=True, disliked=False)
LikeObject.save()
User_Give_Like.inc_num_likes_given()
User_Receive_Like.inc_num_likes_received()
return HttpResponse(200)
To become more specific these two lines of code below are the methods. The problem here is that the first line of code are not actually working but the last line are the only working. Whenever I rearranged these two lines of code the only executed was the last line of code.
....
User_Give_Like.inc_num_likes_given()
User_Receive_Like.inc_num_likes_received()
Example:
In this case, User_Receive_Like.inc_num_likes_given() are working but User_Receive_Like.inc_num_likes_received() are not working and vice-versa.
....
User_Receive_Like.inc_num_likes_received()
User_Give_Like.inc_num_likes_given()
The expected output is both fields num_likes_given and num_likes_received must incremented by 1.

related objects queries django rest framework

I have the following models
class STUser(AbstractBaseUser):
email = models.EmailField(unique=True)
name = models.CharField(max_length=255)
companyname = models.CharField(max_length=200, blank=True, null=True)
...
class VenuePermissions(models.Model):
user = models.ForeignKey(STUser, on_delete=models.CASCADE)
venue = models.ForeignKey(Venue, on_delete=models.CASCADE)
signupvaildatestring = models.CharField(max_length=200, blank=True, null=True)
...
I want to grab all the STUser objects and grab all their permissions.
So what I would like is to grab all the VenuePermissions objects. And grab the user and venue object of each venuePermission
Two ways I can do this. use the VenuePermissions_set attribute on STUser but then how do I grab the venue when its just going to be a pk value?
Or focus on the VenuePermissions objects and grab the user and venue from the pk values but how?
I remember nested queries, and I kinda did one in my browse code.
here is an example:
rooms = Room.objects.filter(venue=OuterRef('pk'), sixtyroundseatingoption= True)
venuelist = venuelist.annotate(sixtyrounds=Exists(rooms))
venuelist = venuelist.filter(Q(sixtyrounds = True) | Q(fullbuyoutsixtyroundseatingoption = True))
I've done the set objects in a serializer before
Example serializer:
class RoomAndImageSerializer(serializers.ModelSerializer):
roomimage_set = RoomImageSerializer(many=True, read_only=True)
class Meta:
model = Room
fields = ('pk','name')
any help with this query would be appreciated!
So this is what I am currently trying, I will post an answer if this works:
class VenueUserList(ListAPIView):
serializer_class = VenueUserListSerializer
queryset = VenuePermissions.objects.select_related('user').select_related('venue').filter(signupvaildatestring=None)
class VenueUserListSerializer(serializers.ModelSerializer):
user = UserSerializer()
venue = VenueSerializer()
class Meta:
model = VenuePermissions
fields = ('user', 'venue', 'isvenueviewer', 'isvenueeventplanner', 'isvenueadministrator')
Here is the answer. However I still need to group venues by user. Working on that.
class VenueUserList(ListAPIView):
serializer_class = VenueUserListSerializer
queryset = VenuePermissions.objects.select_related('user').select_related('venue').filter(signupvaildatestring=None)
class VenueUserListSerializer(serializers.ModelSerializer):
user = UserSerializer()
venue = VenueSerializer()
class Meta:
model = VenuePermissions
fields = ('user', 'venue', 'isvenueviewer', 'isvenueeventplanner', 'isvenueadministrator')

Django REST framework, dealing with related fields on creating records

Preliminary note: this is a rather newbie question, though I have not found a sufficient answer on StackOverflow; many similar questions, but not this one. So I am asking a new question.
The problem: I'm having difficulty creating records where one field is a foreign key to an existing record, and I do not know what I'm doing wrong in my code.
In my app there are two models in question, a one-to-many relationship between Company and BalanceSheet:
models:
class Company(models.Model):
cik = models.IntegerField(default=0, unique=True)
symbol = models.CharField(max_length=4, unique=True)
name = models.CharField(max_length=255, unique=True)
def __str__(self):
return self.symbol
class BalanceSheet(models.Model):
company = models.ForeignKey(Company,
null=True,
on_delete=models.CASCADE,
related_name='balance_sheets',)
date = models.DateField()
profit = models.BigIntegerField()
loss = models.BigIntegerField()
class Meta:
unique_together = (('company', 'date'),)
def __str__(self):
return '%s - %s' % (self.company, self.date)
serializers:
class BalanceSheetSerializer(serializers.ModelSerializer):
company = serializers.StringRelatedField()
class Meta:
model = BalanceSheet
fields = ('company','date','profit','loss')
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ('cik', 'symbol', 'name')
Views:
class BalanceSheetCreate(generics.CreateAPIView):
model = BalanceSheet
queryset = BalanceSheet.objects.all()
serializer_class = BalanceSheetSerializer
urls include:
url(r'^(?P<symbol>[A-Z]{1,4})/create-balance-sheet/$', views.BalanceSheetCreate.as_view(),
name='create_balance_sheet'),
To this point, I have zero problem reading data. However, when trying to create records, I get errors I don't understand:
curl http://localhost:8000/financials/AAPL/create-balance-sheet/ -X POST -d "company=AAPL&date=1968-04-17&profit=1&loss=1"
IntegrityError at /financials/AAPL/create-balance-sheet/
null value in column "company_id" violates not-null constraint
Dropping the company data from that curl command results in the same error.
How do I get around this error? I thought I was telling the api what company I'm interested in, both explicitly in the url and in the post data.
Using python3.6, django 1.11, and djangorestframework 3.7.7
You get the IntegrityError because your code will try to create a new BalanceSheet without a company. That's because StringRelatedField is read-only (see docs) and therefore it's not parsed when BalanceSheetSerializer is used in write mode.
SlugRelatedField is what you need here:
class BalanceSheetSerializer(serializers.ModelSerializer):
company = serializers.SlugRelatedField(slug_field='symbol')
class Meta:
model = BalanceSheet
fields = ('company','date','profit','loss')
To answer my own question, here's what I wound up with. Thanks again go to dukebody.
models:
class Company(models.Model):
cik = models.IntegerField(default=0)
symbol = models.CharField(max_length=4)
name = models.CharField(max_length=255)
def __str__(self):
return self.symbol
class BalanceSheet(models.Model):
company = models.ForeignKey(Company,
null=True,
on_delete=models.CASCADE,
related_name='balance_sheets',)
date = models.DateField()
profit = models.BigIntegerField()
loss = models.BigIntegerField()
class Meta:
unique_together = (('company', 'date'),)
def __str__(self):
return '%s - %s' % (self.company, self.date)
serializers:
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ('cik', 'symbol', 'name')
class BalanceSheetSerializer(serializers.ModelSerializer):
company = CompanySerializer(many=False)
class Meta:
model = BalanceSheet
fields = ('company', 'date', 'profit', 'loss')
def create(self, validated_data):
company_data = validated_data['company']
company, created = Company.objects.get_or_create(**company_data)
validated_data['company'] = company
sheet = BalanceSheet.objects.create(**validated_data)
return sheet
I also had to include the full company data within my curl statement as a nested dict.