Accessing nested ids in Queryset Django Rest Framework - django

how can i access the category_id? I want to create a list of similar products based on category. So each time i make a get request f.e products/1052/similarproducts, i want to get all the ProductsInStore of the same category as ProductInStore(id=1052) and exclude the ProductInStore(id=1052), my current code gives me "ecommerce.models.ProductInStore.DoesNotExist: ProductInStore matching query does not exist."
Even though a productInStore of 1052 exists.
class ProductInStore(models.Model):
product = models.ForeignKey('Product', on_delete=models.CASCADE)
class Product(models.Model):
name = models.CharField(max_length=200)
product_category = models.ManyToManyField(EcommerceProductCategory)
class SimilarProductsListApiView(generics.ListAPIView):
queryset = ProductInStore.objects.all()
serializer_class = ProductInStoreSerializer
#products/954/similarproductsr
def get_queryset(self):
product_id = self.kwargs['pk']
category = ProductInStore.objects.values_list('product__product_category', flat=True).get(product_id=product_id)
return ProductInStore.objects.filter(product__product_category=category).exclude(product_id=product_id).all()

Your product_id were id of ProductInStore instance, not Product instance and because their ids most likely vary, you could not get instance
class SimilarProductsListApiView(generics.ListAPIView):
queryset = ProductInStore.objects.all()
serializer_class = ProductInStoreSerializer
def get_queryset(self):
product_in_store_id = self.kwargs['pk']
category = ProductInStore.objects.get(id=product_in_store_id).product.product_category
return ProductInStore.objects.filter(product__product_category=category).exclude(id=product_in_store_id)

Related

How to remove results with same value with django ORM?

I have a query that returns data that will be displayed in the browser as a line chart.
Depending on the period chosen, this can represent a rather huge number of results (~25K max).
Most of the time these values do not change, on average on 25 000 results I have about 8000 different values. I think it would be a real optimization if I only return these 8000 values instead of the 25 0000.
My Model:
class TechnicalData(models.Model):
name = models.CharField(_('Name'), max_length=80)
value = models.CharField(_('Value'), max_length=80)
value_type = models.CharField(_('Value type'), max_length=20)
date_time = models.DateTimeField(_("timestamp"))
machine = models.ForeignKey("machine.Machine",
verbose_name = _("machine"),
related_name="technical_data_machine",
on_delete=models.CASCADE)
class Meta:
verbose_name = _("TechnicalData")
verbose_name_plural = _("TechnicalDatas")
ordering = ["-date_time"]
def __str__(self):
return self.name
If the "value" field does not change during a given period (date_time), I would like to remove the "duplicate/same" values.
Today I have this view:
class TechnicalDataViewSet(viewsets.ViewSet):
"""
A simple ViewSet for listing or retrieving technical data.
"""
permission_classes = [permissions.IsAuthenticated]
pagination_class = LargeResultsSetPagination
def list(self, request):
id_machine = self.request.query_params.get('id_machine')
name = self.request.query_params.get('name')
only_last = self.request.query_params.get('only_last')
names = self.request.query_params.get('name__in')
date_start = self.request.query_params.get('date_start')
date_end = self.request.query_params.get('date_end')
queryset = TechnicalData.objects.all()
if id_machine:
queryset = queryset.filter(machine__id=id_machine)
if name:
queryset = queryset.filter(name=name)
if names:
names = names.split(',')
queryset = queryset.filter(name__in=names)
if date_start:
queryset = queryset.filter(date_time__date__gte=date_start)
if date_end:
queryset = queryset.filter(date_time__date__lte=date_end)
if only_last:
queryset = queryset.order_by('name', '-date_time').distinct("name")
pagination = LargeResultsSetPagination()
qs = pagination.paginate_queryset(queryset, request)
serializer = TechnicalDataSerializer(qs, many=True)
return Response(serializer.data)
Is it possible to send only the different results?
if you are looking for a way to return distinct values of your queryset, django has a good method on queryset conveniently named distinct. here is a documentation on how to use it.
django distinct

filter access to detailview by a simple field and/or a manytomanyfield

I want to limit the access to detailView of a chatroom to the owner and participants of the room(joiners)
model:
class PublicChatRoom(models.Model):
title = models.CharField(max_length=100, unique=True, blank=False)
owner = models.ForeignKey(User,related_name='chatrooms_created',on_delete=models.CASCADE)
joiners = models.ManyToManyField(User, blank=True,related_name='chatrooms_joined')
view:
class JoinerRoomDetailView(DetailView):
model = PublicChatRoom
template_name = 'detail.html'
def get_queryset(self):
return PublicChatRoom.objects.filter(Q(joiners__in=[self.request.user]) | Q(owner=self.request.user))
and some rooms give the following error :
get() returned more than one PublicChatRoom -- it returned 2!
if I use the view like this:
class JoinerRoomDetailView(DetailView):
model = PublicChatRoom
template_name = 'detail.html'
def get_queryset(self):
return PublicChatRoom.objects.filter(Q(joiners__in=[self.request.user])) #the modified part
only if the user that is in participant list have access, which is correct
and if it's that:
class JoinerRoomDetailView(DetailView):
model = PublicChatRoom
template_name = 'detail.html'
def get_queryset(self):
return PublicChatRoom.objects.filter(Q(owner=self.request.user)) #the modified part
only the creator of room can see it, again correct everything works as expected.
but the Goal is to access rooms that a user own or a part of both, so how can I do that?
Because you have an "OR" clause that will both return a record, you need to make sure you return "distinct" records
class JoinerRoomDetailView(DetailView):
model = PublicChatRoom
template_name = 'detail.html'
def get_queryset(self):
return PublicChatRoom.objects.filter(Q(joiners__in=[self.request.user]) | Q(owner=self.request.user)).distinct()

How to check a condition in a DRF Serializer and then skip that iteration and go to the next

I have a serializer as follows:
class CustomerSerializer(serializers.ModelSerializer):
product = serializers.SerializerMethodField()
def get_product(self, obj):
obj.product = Customer.check_is_product(obj.product_id)
return obj.product.name
class Meta:
model = Customer
fields = ['name', 'product']
and I have a models.py as follows:
class Product(models.Model):
name = models.IntegerField()
class Meta:
db_table = 'products'
class Customer(models.Model):
name = models.CharField(max_length=255)
product_id = models.IntegerField()
class Meta:
db_table = 'customers'
#staticmethod
def check_is_product(id)
try:
product_obj = Products.objects.get(id=id)
except:
<if product with that id isn't there, then i wanna skip that iteration in serializer>
return product_obj
Now imagine I have three customers in my Database, out of that, one customer doesn't have any product, then I wanna skip that entire customer's detail in my API response. So my final API response would have a list with only 2 items. Does anyone know how to skip an iteration of the serializer on any condition check?
You can handle the logic within your view.
Option 1: Create a custom view for that type of request.
Option 2: Send a query parameter as a flag for that type of request to your current view.
Option 3: Just edit the current view with the logic to filter however you want.
Example for option 1, that would return a queryset with all Customers that have a product id greater than 0:
queryset = Customer.objects.all(product_id__gt=0)
Also, in Customer.product_id, I would recommend switching from models.IntergerField() to models.ForeignKey(Product, on_delete=models.PROTECT, null=True, blank=True).
Edit: More in Depth answer, editing a viewset to get the queryset you want.
class CustomerViewSet(viewsets.ModelViewSet):
serializer_class = CustomerSerializer
def get_queryset(self):
queryset = Customer.objects.all(product_id__gt=0)
return queryset

How to overwrite get method in generic RetrieveAPIView in django rest framework to filter the results

I have an API that can list several buildings. Each building belongs to several building groups and each building group contains several buildings.
I want to show single fields of one building group. More specifically I want to show all buildings of one building group in my RetrieveAPIView.
I can list a single BuildingGroup instance using the generic view like so:
class BuildingGroupRetrieveAPIView(RetrieveAPIView):
serializer_class = BuildingGroupSerializer
queryset = BuildingGroup.buildings.all()
I assume that I can overwrite the get method to only display a single field of that retrieved object. Specifically I want to display all the objects that are in my many to many relation. Or better to say, I want to retrieve all the complete data within my m2m relation.
Here are my models:
class Building(models.Model):
name = models.CharField(max_length=120, null=True, blank=True)
def __str__(self):
return self.name
class BuildingGroup(models.Model):
description = models.CharField(max_length=500, null=True, blank=True)
buildings = models.ManyToManyField(Building, default=None, blank=True)
I tried this without success:
def get(self):
building_group = BuildingGroup.objects.get(id='id')
qs = building_group.buildings.all()
return qs
my serializer
class BuildingGroupSerializer(serializers.ModelSerializer):
class Meta:
model = BuildingGroup
fields = (
'description',
.....
)
I can attach a screenshot to be more clear.
Any help is highly appreciated. Thanks in advance
Here is my full view:
class BuildingGroupAPIView(ListAPIView):
permission_classes = [permissions.IsAdminUser]
authentication_classes = [SessionAuthentication]
serializer_class = BuildingGroupSerializer
passed_id = None
def get_queryset(self):
qs = BuildingGroup.objects.all()
query = self.request.GET.get('q')
if query is not None:
qs = qs.filter(name=query)
return qs
class BuildingGroupRetrieveAPIView(RetrieveAPIView):
serializer_class = BuildingGroupSerializer
queryset = BuildingGroup.buildings.all()
def get(self):
building_group = BuildingGroup.objects.get(id='id')
qs = building_group.buildings.all()
return qs

django orm latest item group by each foreign key

We have following models:
class Publisher(models.Model):
name = models.CharField(max_length=32)
local_name = models.CharField(max_length=32)
url_pattern = models.CharField(max_length=128)
enabled = models.BooleanField(default=True)
home_page = models.BooleanField(default=False)
category = models.ForeignKey(NewspaperCategory, null=True)
class Newspaper(models.Model):
class Meta:
unique_together = ("publisher", "date")
ordering = ("-date",)
publisher = models.ForeignKey(Publisher)
image = models.ImageField(upload_to=newspaper_upload_to)
thumbnail = models.ImageField(upload_to=newspaper_thumbnail_upload_to)
date = models.DateField()
I have a APIView (Django rest framework) and there are several different query parameters which filter the output of API. I'd like to have a "latest" query parameter which lists only the latest version of each publisher. Also, I need to be able to do further filtering and slicing on that QuerySet before evaluating it.
But the result of query should be Newspaper instances not dict so I can feed them to my serializer.
My view looks like this at the moment :
class Newspapers(APIView):
def get(self, request):
queryset = models.Newspaper.objects.filter(deleted=False).prefetch_related('publisher')
if "latest" in request.GET:
# doing something here with queryset
if "publisher_id" in request.GET:
queryset = queryset.filter(publisher_id=request.GET['publisher_id'])
if "category" in request.GET:
queryset = queryset.filter(publisher__category_id=request.GET['category'])
if "before" in request.GET:
queryset = queryset.filter(date__lt=request.GET['before'])
if "after" in request.GET:
queryset = queryset.filter(date__gte=request.GET['after'])
if "home_page" in request.GET:
queryset = queryset.filter(publisher__home_page=request.GET['home_page'].lower() == 'true')
queryset = queryset.order_by('-date', 'publisher__order')
return PagingResponse(
request,
serializers.NewspaperVersionSerializer,
query=queryset,
identifier_name='date'
)
We can do this with two queries:
if "latest" in request.GET:
latest_ids = list( # <-- first query
queryset.order_by('id')
.values('publisher_id')
.annotate(id=Max('id'))
.values_list('id', flat=True)
)
queryset = queryset.filter(id__in=latest_ids) # <-- second query
the first query gets list of latest newspaper group by publisher, and the second query gets a queryset of those newspaper for further filtering, slicing and ...