Group by day in django admin? - python

I need to group and count events by day in the django admin.
Here's my current admin queryset:
class TransactionLogAdmin(ExportMixin, OrganizationRestrictedAdmin):
list_display = ['get_type_count', 'get_count']
def get_queryset(self, request):
return TransactionLog.objects.all().extra(
select={'day': 'date( date_created )'}).values('datetime')
But I'm getting the following error:
'dict' object has no attribute '_meta'

This is the problem
return TransactionLog.objects.all().extra(
select={'day': 'date( date_created )'}).values('datetime')
you have get_queryset method in the admin. As the name suggests, that method is expected to return a queryset. But you are returning a dictionary here. Remove the call to values()
When over riding get_queryset, it's always a good idea to call the method in the superclass and make modifications to it instead of making a new queryset of your own.

Related

How to return a group by query via Django REST API?

I have a Django REST API which works perfectly when I want to query some data from the database.
Here I have an example:
views.py
class ProductListAPIView(generics.ListAPIView):
def get_queryset(self):
# Collect data from products table and filter it
queryset = Product.objects.filter(name="Ferrari", date__lte="2022-08-01") # <- Substitute with line below
return queryset
serializer_class = ProductSerializer
authentication_classes = [authentication.SessionAuthentication, authentication.TokenAuthentication]
permission_classes = [IsOwnerPermission]
serializers.py
from rest_framework import serializers
from insert_data.models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ["name","category","date","price"]
The output is what I expect i.e. a json response with the content of the database.
The problems arise when I try to group the queryset in order to return the average price of a product. By doing some research in the internet I noticed that I just need to substitute the line of code in the views.py script with this:
Product.objects.filter(name=params['name'], date__lte=query.date).values('name','category').annotate(price_average=Avg('price')).order_by()
I am pretty confident that this does the work, however the API returns an error which I do not know how to fix:
AttributeError: 'int' object has no attribute 'pk'
I totally have no idea what this refers to. Would you be able to suggest a smart and elegant way to return the average price of a product after a group by operation via the REST API?
Is category a ForeignKey to a model? I think the problem is with this field in that case.
I believe that when you call .values() you get the id of foreignKey-fields and you can't access that field as an object anymore.
So REST Framework is trying to access the property pk on what it thinks is an instance of Category.
To fix this you can create a custom serializer where category is an integer instead and you've added price_average. You have to check the field types, I don't know what types you have.
class ProductPriceAverageSerializer(serializers.Serializer):
category = serializers.IntegerField()
price_average = serializers.FloatField()

get last instance of model which contains request.user in manytomanyfield

I am building a BlogApp and I am trying to get the last instance of model in which request.user in ManyToManyField
I have tried using
models.py
class Blog(models.Model):
title = models.CharField(max_length=3000)
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='post_likes')
views.py
def get_data(request):
get_last_blog = Blog.objects.filter(likes__in=[request.user]).last()
print(get_last_blog)
But it is showing first instance not last. I have tried without list like likes__in=request.user but it shows
'User' object is not iterable
I have tried many times but it is still not working. I am new in django. Any help would be much Appreciated. Thank You in Advance
.last() gets last or None object from queryset, so it's based on your order_by. I think you should be using .latest('<your_timestamp_field') and it will get latest object based on that timestamp field. Remember that .latest() can raise ObjectDoesNotExist exception if queryset is empty

Django: trying to understand how the queryset attribute works in class-based generic views

When using class-based generic views in Django, having a queryset attribute means to "restrict" the collection of object the view will operate on, right?
If queryset is provided, that queryset will be used as the source of objects. (Django's get_object())
Model:
from django.db import models
class Person(models.Model):
full_name = models.CharField(max_length=30)
is_active = False
View:
from django.views.generic import DetailView
from books.models import Person
class PersonDetail(DetailView):
queryset = Person.objects.filter(is_active=True)
The queryset above makes sure to only consider objects with is_active=true.
But how does this works internally?
For example: Does Django appends a SQL condition AND is_active=TRUE to every query in the view?
Ok that last example seems pretty stupid but I hope you get the idea of my question. Thank you.
Yes, this is exactly what happens. Your queryset is used as the base queryset by the view's get_object method. It then applies an additional filter to get a specific object (e.g., by ID):
queryset = queryset.filter(pk=pk)
Of course, the view needs a single object, not a queryset, so it then does:
obj = queryset.get()
Which will either return a single object, or a DoesNotExist or MultipleObjectsReturned exception. DoesNotExist results in a 404. MultipleObjectsReturned is unhandled and will propagate to your code.

What is wrong with the custom method in DetailView

I am trying to compare the PK in the URL with the request.user.id so that no one can view other's profile. This might not be the conventional way to do it, but I'd still like to know what is wrong with my code. I'm a new learner so bear with me.
views.py
class UserDetail(DetailView):
queryset = Profile.objects.all()
template_name = 'details.html'
def get_queryset(self):
if self.request.user.id != self.kwargs['pk']:
queryset = Profile.objects.first()
return queryset
else:
return self.queryset
models.py
class Profile(AbstractUser):
type = models.CharField(max_length=50)
urls.py
url(r'^details/(?P<pk>\d+)/$', login_required(views.UserDetail.as_view())),
When I go to the URL:
ERROR
Exception Type: AttributeError
Exception Value: 'Profile' object has no attribute 'filter'
A Profile instance is not a queryset.
You shouldn't be overriding get_queryset, you should be overriding get_object, which returns the specific object you want to display.

Django filtering and deleting

I have this modelViewSet
class LikeViewSet(viewsets.ModelViewSet):
queryset = Likes.objects.all()
serializer_class = LikeSerializer
filter_fields = ('user','post')
def delete(self, request, pk, format=None):
post = Likes.objects.get(pk=pk)
post.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
I'm trying to filter using the url such as:
http://localhost:8000/likes/?user=anon&post=1
And then delete that specific result that I get from django but django keeps on giving me
delete() takes at least 3 arguments (2 given)
I can't really figure out why. Can anyone help please? Thanks! I'm using Django Rest Framework
EDIT: This is the model for the LikeViewSet:
class Likes(models.Model):
user = models.ForeignKey(Profile, related_name='liker')
post = models.ForeignKey(Post, related_name=' post' )
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('created',)
The idea is, it's a model table for a relationship between a user model and a post model so the filtering has to be done in the url that way
When you're using a ViewSet, you should use the destroy() method rather than delete().
See documentation here:
A ViewSet class is simply a type of class-based View, that does not
provide any method handlers such as .get() or .post(), and instead
provides actions such as .list() and .create().
Based on your code, it doesn't look like you're doing anything unique in the destroy/delete method. Are you fine with just using the default destroy function?

Categories