How to remove results with same value with django ORM? - django

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

Related

Accessing nested ids in Queryset Django Rest Framework

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)

How to add Q lookups with the get_queryset in Django rest framework?

I have written some filtering code in get_queryset function. Also I have a separate search filter api which searches based on the string provided in the query parameter search. Now what I want is add the search query into the former filtering logic so that user can search only in the filtered results and not from the whole database again.
My model:
class Product(models.Model):
WARRANTY = (
('no_warranty', 'No Warranty',),
('local_seller_warranty', 'Local Seller Warranty',),
('brand_warranty', 'Brand Warranty',),
)
merchant = models.ForeignKey(Seller,on_delete=models.CASCADE,blank=True,null=True)
category = models.ManyToManyField(Category, blank=False)
sub_category = models.ForeignKey(Subcategory, on_delete=models.CASCADE,blank=True,null=True)
mini_category = models.ForeignKey(Minicategory, on_delete=models.SET_NULL, blank=True, null=True)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
featured = models.BooleanField(default=False) # is product featured?
/.........other codes.........../
My filtering view:
class ProductAPIView(ListAPIView):
permission_classes = [AllowAny]
serializer_class = ProductSerializer
queryset = Product.objects.all()
pagination_class = CustomPagination
def get_queryset(self):
brand = self.request.GET.get('brand', None)
sub_category = self.request.GET.get("sub_category", None)
warranty = self.request.GET.get("warranty", None)
if brand is not None:
brand_values = brand.split(",")
if sub_category is not None:
sub_category_values = sub_category.split(",")
if warranty is not None:
warranty_values = warranty.split(",")
return Product.objects.filter(brand__name__in=brand_values,
sub_category__name__in=sub_category_values,
warranty__in=warranty_values)
/..........other codes........../
My url to call this
localhost/api/products?brand=Samsung,Lg&warranty=no_warranty
Q lookup search view:
from django.db.models import Q
class PrdouctSearchAPIView(ListAPIView):
permission_classes = [AllowAny]
queryset = Product.objects.all()
serializer_class = ProductSerializer
pagination_class = CustomPagination
def get_queryset(self):
qur = self.request.query_params.get('search')
item = Product.objects.filter(Q(category__name__icontains=qur) |
Q(brand__name__icontains=qur) |
Q(description__icontains=qur) |
Q(collection__name__icontains=qur) |
Q(name__icontains=qur) |
Q(variants__color__icontains=qur)).distinct()
return item
url to perform this view:
localhost/api/productsearch?search=frontload
Now what I want is to combine the two apis like localhost/api/products?brand=Samsung I need to display only Samsung brands machines. Now when I add search=frontload in the same api localhost/api/products?brand=Samsung&search=frontload like I need to display samsung machines with frontload only. how to achieve it??
You can also have different combination with Pipe(|) and, And(&) like this:
super(YourClass, self).get_queryset.filter(Q(industry__icontains=industry) | Q(size_of_company__icontains=size_of_comapany) & Q(liquidity__icontains=liquidity))

Django FilterSet with distinct AND order_by

I want to use django-filter to create a FilerSet with distinct results for field A (Minutes.case), ordered by field B (case__case_filed_date). Database is PostgreSQL.
Commented lines in class MinutesListView are things I've tried (in various configurations).
models.py
class Case(models.Model):
case_filed_date = models.DateField()
case_number = models.CharField(max_length=25, unique=True)
as_of_timestamp = models.DateTimeField()
def __str__(self):
return self.case_number
class Minutes(models.Model):
case = models.ForeignKey(Case, on_delete=models.CASCADE)
minute_entry_text = models.TextField(blank=True, null=True)
minute_entry_date = models.DateField(blank=True, null=True)
minute_entry_type_text = models.CharField(max_length=255, blank=True, null=True)
filters.py
class MinuteFilterSet(df.FilterSet):
case__case_number = df.CharFilter(lookup_expr='icontains', label='Case Number', distinct=True)
minute_entry_text = df.CharFilter(lookup_expr='icontains', label='Minutes Text')
class Meta:
model = Minutes
fields = ['minute_entry_text']
order_by = ['-case__case_filed_date']
views.py:
class FilteredListView(ListView):
filterset_class = None
def get_queryset(self):
# Get the queryset however you usually would. For example:
queryset = super().get_queryset()
# Then use the query parameters and the queryset to
# instantiate a filterset and save it as an attribute
# on the view instance for later.
self.filterset = self.filterset_class(self.request.GET, queryset=queryset)
# Return the filtered queryset
return self.filterset.qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Pass the filterset to the template - it provides the form.
context['filterset'] = self.filterset
return context
class MinutesListView(FilteredListView):
filterset_class = filters.MinuteFilterSet
paginate_by = 25
# ordering = '-case__case_filed_date'
# queryset = Minutes.objects.all()
queryset = Minutes.objects.distinct('case')
The current code shows distinct, unordered results. When I'm able to get ordered results, the cases (case_number) is duplicated. I've read the docs regarding distinct() with order_by() in Django/PostGreSQL but I'm still missing something.

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 ...