annotate result not included in Json response - python

I want to count votes as per Model, and its working fine when i test this query in Django shell but when passing as a json i cannot see the column total_votes when i get Json Response.
class Model(models.Model):
title = models.CharField(max_length=255, null=False, blank=False)
description = models.TextField(null=False, blank=False)
class ModelVote(models.Model):
model = models.ForeignKey(Model, on_delete=models.CASCADE)
vote = models.BooleanField()
created_at = models.DateTimeField(auto_now_add=True)
from django.core.serializers import serialize
class ModelList(View):
def get(self, *args, **kwargs):
models = Model.objects.annotate(total_votes=Count('modelvote'))
return HttpResponse(serialize("json", models), content_type='application/json')

This is a known limitation of the serialization framework
http://code.djangoproject.com/ticket/5711

Below query solved my issue of total_votes not passing as Json Response. just adding .values() worked.
Model.objects.annotate(total_votes=Count('modelvote')).values()
return JsonResponse({'models': list(models)}, status=200)

Related

In Django Rest Api, how do you return only the Items the owner uploaded

The Viewset def list looks like this:
class ThreeDimensionalModelViewSet(viewsets.ViewSet):
serializer_class = ThreeDimensionalModelSerializer
queryset = ThreeDimensionalModel.objects.all()
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def list(self, request):
models = ThreeDimensionalModel.objects.all()
serializer = ThreeDimensionalModelSerializer(models, many=True)
print(request.user.id)
return Response(serializer.data)
The serializer looks like this:
class ThreeDimensionalModelSerializer(serializers.ModelSerializer):
class Meta:
model = ThreeDimensionalModel
fields = ['File', 'Uploaded', 'Owner', 'Previous', 'SharedWithUser']
read_only_fields = ['Owner']
The model looks like this:
class ThreeDimensionalModel(models.Model):
File = models.FileField(upload_to='models')
Owner = models.ForeignKey('auth.User', on_delete=models.SET_NULL, null=True, related_name='Owner')
Uploaded = models.DateTimeField(auto_now_add=True)
Previous = models.ForeignKey("self", on_delete=models.SET_NULL, default=None, null=True)
SharedWithUser = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='SharedWithUser')
When a user requests models at /api/models it should only show the models that are the same owner Id as his.
If no additional data is sent with that request then obviously you can't filter by user.
The straightforward way to do it is that for logged in users the cookie will contain user information such as userId.
When your endpoint recognizes the user who made the requested is logged in, it will use that as the filter for the query instead of all() as seen in the Django docs
https://docs.djangoproject.com/en/3.2/topics/db/queries/#retrieving-specific-objects-with-filters
To summarize - if the user is not logged in (or supplies the information as part of the request in some way) then the request is anonymous and there is no way to know who made it

How can i handle django nested models?

I have a User, Post and Tag model in Django. Tag model is not relevant for this topic. I can get all the data to the front end with nested objects. In the other hand when i want to create a new post i send the post data to django and in django view i am trying to update the data with relating the logged user to the "Post" but when i do that it gives me;
{'owner': {'username': [ErrorDetail(string='A user with that username already exists.', code='unique')]}}
error. How can i solve this error ?
models.py;
class Post(models.Model):
# Post specs
title = models.CharField(max_length=100, null=False)
place = models.CharField(max_length=100, null=False)
notes = models.CharField(max_length=10000, null=False)
tags = models.ManyToManyField(Tag)
start_date = models.DateField(null=True)
end_date = models.DateField(null=True)
created_at = models.DateField(auto_now=True)
owner = models.ForeignKey(User , null = True, on_delete=models.SET_NULL)
serializers.py;
class PostSerializer(serializers.ModelSerializer):
tags = serializers.SlugRelatedField(
many=True,
queryset=Tag.objects.all(),
slug_field='name'
)
owner = UserSerializer()
class Meta:
model = Post
fields = ('title','place','notes','start_date','end_date','created_at','id','owner','tags')
By the way if i change serializer.py like
owner = UserSerializer
it gives just primary key value. In front end i cant to anything with a integer number and i dont want to make an another api call for user model. Lastly view post function;
def post(self, request, format =None):
"""
Creates a post
"""
post = request.data ## copy dictionary to a variable
authenticatedUserDataAsDict = request.user.__class__.objects.filter(pk=request.user.id).values().first()
post.update( {'owner': authenticatedUserDataAsDict} ) ## attach authenticated user to post end
serializer = PostSerializer(data = post) ## serialize the dict
if serializer.is_valid():
serializer.save() ## if data valid save it.
return Response(serializer.data, status = status.HTTP_201_CREATED)
print("not valid->",serializer.errors)
return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST) # if it's not raise http 400
SOLVED
Hi again, it seems that rest framework have no idea about our request(create or get wise) because we are dealing with nested serializers.
So i found this article in medium and it helped me to solve my problem.

filter by is_active boolean field in django

I want to have an is_active field for all the models in my application and when ever I create an api, I want to filter only the active ones and send the response. Is there a generic way to do this? As of now I am keeping a boolean field is_active and every time I retrieve the objects, I am writing a filter. below is the code :
My models.py
class Crew(models.Model):
crew_id = models.AutoField(primary_key=True)
crew_code = models.CharField(max_length=200, null=False, unique=True)
crew_name = models.CharField(max_length=200, null=False)
crew_password = models.CharField(max_length=200, null=False)
is_active = models.BooleanField(default=True)
My views.py :
#api_view(['GET'])
def get_crews(request):
c = Crew.objects.filter(is_active=True)
serializer = CrewSerializer(c, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
You can write custom model manager:
class IsActiveManager(models.Manager):
def get_queryset(self):
return super(IsActiveManager, self).get_queryset().filter(is_active=True)
class Crew(models.Model):
...
objects = IsActiveManager()
Now Crew.objects.all() will return only is_active record.
You can write a mixin in mixin.py file something like this
class TimeFieldsMixin(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True, db_index=True)
class Meta:
abstract = True
And Import this in your models like this:
class User(TimeFieldsMixin):
// model fields
This will add this fields by default wherever you use this mixin.
Let me know if this is not clear.
Please note that if you have additional Model Managers:
The first manager listed in the model class definition is the one that is used for the admin site and a number of other operations.

How to allow only one User to see "UpdateView"?

I have a Users and Jobs. If some User creates a Job, then and only then he/she can edit some information of this Job.
So he visits the url .../job/update/<id>. If the Job is created by him (the User is a ForeignKey in Job, then he can modify data. Otherwise he gets 404 error.
In view function, I would probably get current Users id and compare this id to Jobs ForeignKey.
But there are many patterns and shortcuts in class views so I'm curious how to do that this way.
class EditOrderView(UpdateView):
model = Job
fields = ['language_from','language_to','level','short_description','notes',
'text_to_translate','file']
template_name = 'auth/jobs/update-order.html'
class Job(models.Model):
customer = models.ForeignKey(User, related_name='orders', help_text=u"Zákazník")
translator = models.ForeignKey(User, related_name='jobs', null=True, blank=True, help_text=u"Prekladateľ")
price = models.FloatField(null=True, blank=True, help_text=u"Cena")
language_from = models.ForeignKey(Language, related_name='jobs_from', null=True)
language_to = models.ForeignKey(Language, related_name='jobs_to', null=True)
...
It looks like you can override .get_object() method and include your own logic:
from django.shortcuts import get_object_or_404
class EditOrderView(UpdateView):
model = Job
...
def get_object(self, queryset=None):
return get_object_or_404(self.model, pk=self.kwargs["pk"], customer=self.request.user)

Django, Ajax + Generic foreign keys

I have a generic foreign key in one of my models:
# models.py
class Tasks(models.Model):
content_type = models.ForeignKey(ContentType, limit_choices_to=tasktype_limits, null=True, blank=True)
object_id = models.PositiveIntegerField(null=True, blank=True, )
target = generic.GenericForeignKey('content_type', 'object_id')
ttype = models.ForeignKey('TaskType')
status = models.CharField(max_length = 60, null=False, blank=False)
comments = models.TextField(null=True, blank=True, )
Now I'd like to fetch all the tasks and it's "targets" with AJAX:
# views.py
def get_tasks(request, task_id):
tasks = Tasks.objects.all()
return HttpResponse(serializers.serialize('json', tasks))`
The Ajax-Call is working so far, but it doesn't return the objects related to the target-field.
How can I do that?
I had serious problems using JSON and Generic Keys, this is the method i used to solve my problem. I first made a list of the thing i need for example:
some_list = [some.pk,some.CONTENT_OBJECT.name] for some in GenericModel.objects.all()]
Then, dump the data with simple json found in django.utils
data = simplejson.dumps(some_list)
and then return the data to the template
return HttpResponse(data, mimetype='aplication/json')
Hope it helps.
Not sure if this is related, but there was a bug reported about the serialization of contenttypes (#7052; see related discussion). I believe it was fixed in Django 1.2. Which version of Django are you using?

Categories