The design of my api is
{
"id": "667c476ca953483493afa265e5d500b0",
"name": "Home"
}
This is the result of GET API. In posting, i want the list of devices to be posted. For example, if user want to post devices to Home group, then the url i have designed is /group/group_token/add(/group/667c476ca953483493afa265e5d500b0/add). The data sending format is
{
"devices":[<device_id1>, <device_id2>]
}
i.e
{
"devices":"[5ac41ba7e6ae4628982b2c81c99343a8], [7nu21ba7e6ae4628982b2c81c99343a8]"
}
Here is my model, serializer and APIView i have done so far
class BaseDevice(PolymorphicModel):
name = models.CharField(max_length=250, blank=False, null=False)
owner = models.ForeignKey(User, blank=False, null=False)
token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
group = models.ForeignKey('DeviceGroup', related_name="groups", null=True, blank=True)
class Device(BaseDevice):
description = models.TextField(blank=True, null=True)
class DeviceGroup(models.Model):
token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
name = models.CharField(max_length=250, blank=False, null=False)
owner = models.ForeignKey(User, blank=False, null=False)
class DeviceGroupSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
class Meta:
model = DeviceGroup
fields = ['id','name']
class DevicesGroupsAPIView(APIView):
permission_classes = (permissions.IsAuthenticated,)
def get_serializer_class(self):
if self.request.user.is_staff:
return DeviceGroupSerializer
def get_object(self, user, token):
try:
return BaseDevice.objects.filter(owner=user).get(token=token)
except ObjectDoesNotExist:
return error.RequestedResourceNotFound().as_response()
def get(self, request, format=None):
reply = {}
try:
groups = DeviceGroup.objects.filter(owner=request.user)
reply['data'] = DeviceGroupSerializer(groups, many=True).data
except:
reply['data'] = []
return Response(reply, status.HTTP_200_OK)
def post(self, request, token=None, format=None):
device_group_instance = DeviceGroup.objects.get(token=token)
for device_token in request.data['devices']:
device = Device.objects.get(token=device_token, owner=request.user)
device.group = device_group_instance
device.save()
How can i do the posting? I get an error on token part. It says
DeviceGroup matching query does not exist.
How should my posting be?
UPDATE
Frist screenshot
The url is device_group/ . When i try to post from there. i get above error not matching query one
Second Screenshot
The url is in the screenshot browser. I dont get device list to post rather i see name field.
I'm not sure how this is supposed to work, but for whatever reason your post() function is not obtaining a valid token that matches an existing DeviceGroup.
Make sure that DeviceGroup is the model you are intending to call.
If you are manually instantiating post() somewhere else, check to see that a valid token is being passed to it.
Otherwise you will need to retrieve it in the function itself. For example, if the token is stored in a session variable, you can do:
def post(self, request, token=None, format=None):
token = request.session.token
device_group_instance = DeviceGroup.objects.get(token=token)
for device_token in request.data['devices']:
device = Device.objects.get(token=device_token, owner=request.user)
device.group = device_group_instance
device.save()
Related
I have this serializer and I use it to get post detail of a post belonging to a user. The owner of the post is not the user that is currently logged in. I want to check if the post is bookmarked by the currently logged in user. The currently logged in user's id is passed in the request but I cannot find it in this context.
Here is the serializer:
class UserPostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, read_only=True, required=False)
profile = serializers.SerializerMethodField()
bookmarked = serializers.SerializerMethodField()
class Meta:
model = Post
fields = [
"id",
"category",
"body",
"images",
"video",
"profile",
"published",
"bookmarked",
"created_at",
"updated_at",
]
depth=1
def get_profile(self, obj):
profile_obj = Profile.objects.get(id=obj.user.profile.id)
profile = ShortProfileSerializer(profile_obj)
return profile.data
def get_bookmarked(self, obj):
breakpoint()
bookmark = Bookmark.objects.filter(owner=obj.user.id, post=obj.id,marktype='post')
if bookmark:
return True
else:
return False
The problem is obj.user.id is the owner of the post. I need the logged in user whose id is passed in the url. Here is the model for the bookmark:
class Bookmark(models.Model):
marktype = models.CharField(max_length=50)
post = models.OneToOneField(Post, on_delete=models.CASCADE, null=True, blank=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")
class Meta:
verbose_name = "bookmark"
verbose_name_plural = "bookmarks"
ordering = ["created_at"]
db_table = "bookmarks"
def __str__(self):
return "{}'s bookmark".format(self.owner.username)
and here is the URL:
path("posts/<int:user>/home/", HomeView.as_view(), name="home"),
This self.context['request'].user returns the owner of the post and not the logged in user.
How do I get the id of the currently logged in user or the user whose id I pass in the URL please?
Maybe do you can use filters to the Viewset:
urls.py
path("posts/home/", HomeView.as_view(), name="home")
viewsets.py
from rest_framework import viewsets
from .models import Post
from .serializers import, UserPostSerializer
from .filters import OwnerFilter
class HomeView(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = UserPostSerializer
filter_backends = (OwnerFilter,)
filters.py
from rest_framework.filters import BaseFilterBackend
class OwnerFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
owner = request.query_params.get('owner', None)
if not owner:
return queryset.all()
else:
try:
return queryset.filter(bookmarked__owner__id=owner)
except Exception:
return queryset.none()
Running
Then access the URL:
/posts/home/?owner=OWNER_ID_HERE
Solved it and you can get any kwargs from the view that handles the request. In my case adding the following to the get_bookmarked function gives me the id I send in the URL:
loggeduser = self.context.get('view').kwargs.get('user')
I'm stuck on fetching data with a related foreign key. I am doing some kind of validation in which the create method would be allowed depending on the requesterid to be POSTed.
This is my userTable model:
class userTable(models.Model):
userid = models.UUIDField(primary_key=True, default = uuid.uuid4, editable=False)
username = models.CharField(max_length=50, null=False, unique=True)
userroleid = models.ForeignKey(roleTable, on_delete=models.CASCADE)
def __str__(self):
return self.username
Another model is the requestTable
class requestTable(models.Model):
rid = models.AutoField(primary_key=True)
requesterid = models.ForeignKey(userTable, on_delete=models.CASCADE)
(...)
This is my serializer:
class RequestCreateSerializer(serializers.ModelSerializer):
parts=PartSerializer(many=True)
class Meta:
model = requestTable
fields = ['rid','requesterid', (...)]
def create(self, instance, validated_data):
if instance.requesterid.userroleid == 3: #how can i fetch my `requesterid` data?
parts_data = validated_data.pop('parts')
request = requestTable.objects.create(**validated_data)
for part_data in parts_data:
partsTable.objects.create(request=request, **part_data)
return request
raise ValidationError("Sorry! Your role has no permission to create a request.")
Also, I'm quite confused if I should do validation in serializers, or views. If I do it in views, it just throws the ValidationError, and it doesn't seem to enter the if condition.
For reference, here's my views:
class RequestListCreateView(ListCreateAPIView):
queryset = requestTable.objects.all()
serializer_class = RequestCreateSerializer
def create(self, request, *args, **kwargs):
if request.data.get('requesterid__userroleid') == '3':
write_serializer = RequestCreateSerializer(data=request.data)
write_serializer.is_valid(raise_exception=True)
self.perform_create(write_serializer)
headers = self.get_success_headers(write_serializer.data)
return Response({"Request ID": write_serializer.instance.requestid, "Parts ID": [p.partsid for p in write_serializer.instance.parts.all()]},headers=headers)
raise ValidationError("Sorry! Your role has no permission to create a request.")
Hope someone can help me!
I'm trying to display all orders matching each logged in user, I dont understand why it gives me issues when trying to filter for users as it gives me that UserCheckout does not have any matching queries:
orders/views.py
class OrderList(LoginRequiredMixin, ListView):
queryset = Order.objects.all()
def get_queryset(self):
user_check_id = self.request.user.id
user_checkout = UserCheckout.objects.get(id=user_check_id)
return super(OrderList, self).get_queryset().filter(user=user_checkout)
orders/mixins.py
class LoginRequiredMixin(object):
#method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(request,*args, **kwargs)
orders/models.py
class UserCheckout(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete = models.CASCADE) # not required as to allow guests to checkout too
email = models.EmailField(unique=True) # required, unique as if there the guest already has an authentication just one email needed
def __str__(self):
return self.email
class Order(models.Model):
status = models.CharField(max_length=120, choices=ORDER_STATUS_CHOICES, default='created')
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
user = models.ForeignKey(UserCheckout, null=True, on_delete=models.CASCADE)
billing_address = models.ForeignKey(UserAddress, related_name='billing_address', null=True,on_delete=models.CASCADE)
shipping_address = models.ForeignKey(UserAddress, related_name='shipping_address', null=True, on_delete=models.CASCADE)
shipping_total_price = models.DecimalField(max_digits=50, decimal_places=2, default=5.99)
order_total = models.DecimalField(max_digits=50, decimal_places=2)
def __str__(self):
return str(self.cart.id)
Error it gives me:
DoesNotExist at /orders/
UserCheckout matching query does not exist.
You are getting an error because you are trying to use the User's primary key (id) as the UserCheckout's primary key i.e. the lines:
user_check_id = self.request.user.id
user_checkout = UserCheckout.objects.get(id=user_check_id)
Change these lines to:
user = self.request.user
user_checkout = UserCheckout.objects.get(user=user)
Also this can throw an Exception if a UserCheckout instance doesn't exist you can catch that using try-except or use django's shortcut function get_object_or_404:
from django.shortcuts import get_object_or_404
user_checkout = get_object_or_404(UserCheckout, user=user)
i am trying to make an app for student but i'm getting this error,
as you can see for convenient i wanted to use like that one i showed bellow but it doesn't work, should i keep using like before? or i could use like that ? what would be best way ?
ValueError at /student/program_structure/
Cannot query "abcd#gmail.com": Must be "Student" instance.
thank you so much :)
models.py
class Student(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
status = models.CharField(max_length=10, choices=STATUS, default='active')
class Program(models.Model):
#everything was fine when used
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True) #this one
#but when using this one i started getting this error from views.py
user = models.ForeignKey(
Student, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200, unique=True)
prefix = models.CharField(max_length=20)
class Course(models.Model):
user = models.ForeignKey(Student, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200, unique=True)
prefix = models.CharField(max_length=20)
code = models.CharField(max_length=20)
subject = models.ManyToManyField('Subject', related_name='subject_list',
blank=True)
views.py
class Program_structure(generic.View):
def get(self, *args, **kwargs):
profile = get_object_or_404(Student, user=self.request.user)
program_structure = Course.objects.filter(student=profile)
# program_structure =
Course.objects.filter(student__user=self.request.user)
credit = Course.objects.filter(student__user=self.request.user).
annotate(total_no=Sum('subject__credit'))
total_credit = self.request.user.course_set.aggregate(
total_credit=Sum('subject__credit')
)['total_credit'] or 0
context = {
'test':program_structure,
'credit':credit,
'profile':profile,
'total_credit' : total_credit
}
return render(self.request, 'program_structure.html', context)
The user field of the Course refers to the Student object, not a User object, so you can not user request.user for this.
You can however query for a Course where the user is a Student where the user is request.user with:
class Program_structure(generic.View):
def get(self, *args, **kwargs):
profile = Student.objects.all()
program_structure = Course.objects.filter(user__user=self.request.user)
context = {
'test':program_structure,
'profile':profile,
}
return render(self.request, 'program_structure.html', context)
You probably also want to set profile to the Student object of the user. In that case, you can reuse the profile when you filter the Courses:
from django.shortcuts import get_object_or_404
class Program_structure(generic.View):
def get(self, *args, **kwargs):
profile = get_object_or_404(Student, user=request.user)
program_structure = Course.objects.filter(user=profile)
context = {
'test':program_structure,
'profile':profile,
}
return render(self.request, 'program_structure.html', context)
It might also be better to rename the user field to student:
class Course(models.Model):
student = models.ForeignKey(
Student,
on_delete=models.SET_NULL,
null=True
)
# …
since that makes it clear that this is a Student, not a User. In that case you filter with:
from django.shortcuts import get_object_or_404
class Program_structure(generic.View):
def get(self, *args, **kwargs):
profile = get_object_or_404(Student, user=request.user)
program_structure = Course.objects.filter(student=profile)
context = {
'test':program_structure,
'profile':profile,
}
return render(self.request, 'program_structure.html', context)
I have am implementing a follower and followers system in my drf api.
My relationship model and serializer:
models.py
class Relationship(models.Model):
user = models.ForeignKey(User, related_name="primary_user", null=True, blank=True)
related_user = models.ForeignKey(User, related_name="related_user", null=True, blank=True)
incoming_status = models.CharField(max_length=40, choices=RELATIONSHIP_CHOICE, default=RELATIONSHIP_CHOICE[0])
def __str__(self):
return self.user.username + " " + self.incoming_status + " " + self.related_user.username
serializers.py
class RelationshipSerializer(serializers.ModelSerializer):
outgoing_status = serializers.SerializerMethodField()
class Meta:
model = models.Relationship
fields = (
'user',
'related_user',
'incoming_status',
'outgoing_status',
)
def get_outgoing_status(self, obj):
related_user = obj.related_user
user = obj.user
try:
query = models.Relationship.objects.get(user=related_user, related_user=user)
user_id = query.incoming_status
except models.Relationship.DoesNotExist:
user_id = "none"
return user_id
views.py
class UserViewSet(viewsets.ModelViewSet):
queryset = models.User.objects.all()
serializer_class = serializers.UserSerializer
#detail_route(methods=['get'], url_path='relationship/(?P<related_pk>\d+)')
def relationship(self, request, pk, related_pk=None):
user = self.get_object()
query = models.Relationship.objects.filter(user=user)&\
models.Relationship.objects.filter(related_user__pk=related_pk)
serializer = serializers.RelationshipSerializer(query, many=True)
return Response(serializer.data)
Incoming status is your relationship to the user and outgoing status is the users relationship to you to so for example this can return
[
{
"user": 2,
"related_user": 1,
"incoming_status": "follows",
"outgoing_status": "none"
}
]
This means you follow the user and the user doesn't follow you back
When you follow a user my code works fine because it returns "incoming_status": "follows" and it then checks for the outgoing status in the serializers. However when the:
query = models.Relationship.objects.filter(user=user) &
models.Relationship.objects.filter(related_user__pk=related_pk)
query in views.py returns null the meaning that the incoming status is none the serializer outputs [] because the query is empty. How do I make incoming_status = "none" if the query is empty?
Thanks in advance