django-filter get queryset - python

I am using django-filter v1.1.0 , django 1.11. I want a dynamic filter for a model. I have created filters.py which contains the respective config for model filters. This site tells that:
It will generate a Django Form with the search fields as well as
return the filtered QuerySet.
It here refers to SomeModelFilter function. I tried applying len and objects functions to it's object, but it returns
AttributeError: 'SomeModelFilter' object has no attribute 'len'
AttributeError: 'SomeModelFilter' object has no attribute 'objects'
I want to get the filtered content. It doesn't seem to be a QuerySet to me.
filters.py
from project_app.models import *
import django_filters
class SomeModelFilter(django_filters.FilterSet):
class Meta:
model = SomeModel
fields = ['field_a', 'field_b', 'field_c', 'field_d']
views.py
somemodel_list = SomeModel.objects.all()
somemodel_filter = SomeModelFilter(request.GET, queryset=somemodel_list)
print(len(somemodel_filter)) # This gives the first error
print(somemodel_filter.objects.all()) # This gives the second error
I want to get the filtered content, hopefully which is contained in somemodel_filter object.

The problem is in this line print(somemodel_filter.objects.all()). somemodel_filter is not model, it's filterset instance and since it's don't have objects attribute. To get filtered queryset use qs attribute, like this:
print(somemodel_filter.qs)
You can find example of filter usage here.

filtered_data = ExampleFilter(requet.Get, queryset=Example.objects.all())
to get the filtered queryset
filtered_queryset_data = filtered_data.qs
Use serializer to serialize the data. Use many=true since the its a list
serialized_data = ExampleSerializer(filtered_queryset_data, many=true).data

Related

Django REST API query on related field

I have 3 models, Run, RunParameter, RunValue:
class Run(models.Model):
start_time = models.DateTimeField(db_index=True)
end_time = models.DateTimeField()
class RunParameter(models.Model):
parameter = models.ForeignKey(Parameter, on_delete=models.CASCADE)
class RunValue(models.Model):
run = models.ForeignKey(Run, on_delete=models.CASCADE)
run_parameter = models.ForeignKey(RunParameter, on_delete=models.CASCADE)
value = models.FloatField(default=0)
class Meta:
unique_together=(('run','run_parameter'),)
A Run can have a RunValue, which is a float value with the value's name coming from RunParameter (which is basically a table containing names), for example:
A RunValue could be AverageTime, or MaximumTemperature
A Run could then have RunValue = RunParameter:AverageTime with value X.
Another Run instance could have RunValue = RunParameter:MaximumTemperature with value Y, etc.
I created an endpoint to query my API, but I only have the RunParameter ID (because of the way you can select which parameter you want to graph), not the RunValue ID directly. I basically show a list of all RunParameter and a list of all Run instances, because if I showed all instances of RunValue the list would be too long and confusing, as instead of seeing "Maximum Temperature" you would see:
"Maximum Temperature for Run X"
"Maximum Temperature for Run Y"
"Maximum Temperature for Run Z", etc. (repeat 50+ times).
My API view looks like this:
class RunValuesDetailAPIView(RetrieveAPIView):
queryset = RunValue.objects.all()
serializer_class = RunValuesDetailSerializer
permission_classes = [IsOwnerOrReadOnly]]
And the serializer for that looks like this:
class RunValuesDetailSerializer(ModelSerializer):
run = SerializerMethodField()
class Meta:
model = RunValue
fields = [
'id',
'run',
'run_parameter',
'value'
]
def get_run(self, obj):
return str(obj.run)
And the URL just in case it's relevant:
url(r'^run-values/(?P<pk>\d+)/$', RunValuesDetailAPIView.as_view(), name='values_list_detail'),
Since I'm new to REST API, so far I've only dealt with having the ID of the model API view I am querying directly, but never an ID of a related field. I'm not sure where to modify my queryset to pass it an ID to get the appropriate model instance from a related field.
At the point I make the API query, I have the Run instance ID and the RunParameter ID. I would need the queryset to be:
run_value = RunValue.objects.get(run=run_id, run_parameter_id=param_id)
While so far I've only ever had to do something like:
run_value = RunValue.objects.get(id=value_id) # I don't have this ID
If I understand correctly, you're trying to get an instance of RunValue with only the Run id and the RunParameter id, i.e. query based on related fields.
The queryset can be achieved with the following:
run_value = RunValue.objects.get(
run__id=run_id,
run_parameter__id=run_parameter_id
)
Providing that a RunValue instance only ever has 1 related Run and RunParameter, this will return the instance of RunValue you're after.
Let me know if that's not what you mean.
The double underscore allows you to access those related instance fields in your query.
Well its pretty simple, all you have to do is override the get_object method, for example(copy pasted from documentation):
# view
from django.shortcuts import get_object_or_404
class RunValuesDetailAPIView(RetrieveAPIView):
queryset = RunValue.objects.all()
serializer_class = RunValuesDetailSerializer
permission_classes = [IsOwnerOrReadOnly]]
lookup_fields = ["run_id", "run_parameter_id"]
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # Ignore empty fields.
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter) # Lookup the object
self.check_object_permissions(self.request, obj)
return obj
# url
url(r'^run-values/(?P<run_id>\d+)/(?P<run_parameter_id>\d+)/$', RunValuesDetailAPIView.as_view(), name='values_list_detail'),
But one big thing you need to be careful, is not to have duplicate entries with same run_id and run_parameter_id, then it will throw errors. To avoid it, either use unique_together=['run', 'run_parameter'] or you can use queryset.filter(**filter).first() instead of get_object_or_404 in the view. But second option will produce wrong results when duplicate entries are created.

storing queryset in session variables

I am using django and trying to store the queryset in session variable
def wholelist(request):
hotelvar=request.POST.get('service_type')
city_list=Hotels.objects.filter(city_name__iexact=request.POST.get('searchabc'))
if not city_list:
hotel_list=Hotels.objects.all()
context={'hotel_list':hotel_list}
return render(request, 'polls/homepage.html',context)
pricemin=200
pricemax=800
request.session['hlist']=city_list
I am getting the following error:
[Hotels: ashoka, Hotels: abc] is not JSON serializable
I tried to convert into list and then store it
request.session['hlist']=list(city_list)
I am getting the following error:
'QuerySet' object has no attribute 'POST'
This is the model structure of hotels
class Hotels(models.Model):
def __str__(self):
return self.hotel_name
hotel_name=models.CharField(max_length=200)
photo=models.ImageField()
city_name=models.CharField(max_length=200)
Is there a way to store queryset in session variable?
For is not JSON serializable error you can serialize your models with django serializers as follows:
from django.core import serializers
hotel_list=Hotels.objects.all()
json_hotel = serializers.serialize('json', hotel_list)
context={'hotel_list':json_hotel}
You can't save QuerySet direct in Django session , u need to serialize it first then you will be able to save it in session.
Let me know if it working with you
Cheers
What I am understanding by your problem is that you want to store all the values returned in a queryset to be stored in the session variable of the request.
But you can not do that as those querysets will be nothing but the reference to the objects.
For if you want to store the values, what you can do is
import json
def wholelist(request):
hotelvar=request.POST.get('service_type')
city_list=Hotels.objects.filter(city_name__iexact=request.POST.get('searchabc'))
if not city_list:
hotel_list=Hotels.objects.all()
context={'hotel_list':hotel_list}
return render(request, 'polls/homepage.html',context)
pricemin=200
pricemax=800
city_list2 = []
city_list_for_session = city_list.values()#this will store the values of querylist to the session
for item in city_list_for_session:
data = {
'hotel':item['hotel'],
'city_name':item['city_name']}
city_list2.append(data)
request.session['hlist']=city_list2
The function .values() will get you a list of all the items with the value of each column in a dictionary.
So basically what you will be getting is a list of dictionary with the values of queryset.
Hope it helps.

Django MySql - combining only() and distinct()

This is my model in Django.
class Meta_Columns(models.Model):
cur_parent=models.CharField(max_length=200)
cur_child=models.CharField(max_length=200)
cur_child_label=models.CharField(max_length=200)
cur_childisparent= models.BooleanField()
cur_childtype= models.CharField(max_length=200,choices=CHILD_TYPE)
cur_Misc= models.CharField(max_length=200,blank=True)
class Admin:
pass
I want to select the 'cur_parent' column and get the distinct values (from MySql)
Below is the code.
if request.method == 'POST':
all_parents = Meta_Columns.objects.only("cur_parent").distinct("cur_parent")
data = serializers.serialize("json", all_parents)
return HttpResponse(data, content_type='application/json')
If i make the call to the view, this is the error i get.
DISTINCT ON fields is not supported by this database backend
I cannot use values("field_name").distinct() because it will not work with json & this error is thrown : 'dict' object has no attribute '_meta'.
How to get distinct values then?
Django's serializers.serialize() expects Django model instances as inputs, and distinct() won't be returning that (even more so because cur_parent is not a ref to a model, but a CharField)
If .values('cur_parent') works for you, you can just serialize that list of distinct parents with a regular JSON serializer, e.g.
import json
all_parents = Meta_Columns.objects....values('cur_parent').distinct()
json_str = json.dumps(all_parents) # Works with regular data structure,
# doesn't need to be a Django model instance
return HttpResponse(json_str, content_type='application/json')

Returning extended fields in JSON

I have two tabels(Ingredient_Step and Ingredient) in on relation as you can see below:
Models.Py
class Ingredient_Step(models.Model):
ingredient = models.ForeignKey(Ingredient)
Step = models.ForeignKey(Step)
def __unicode__(self):
return u'{}'.format(self.Step)
class Ingredient(models.Model):
IngredientName = models.CharField(max_length=200,unique=True)
Picture = models.ImageField(upload_to='Ingredient')
def __unicode__(self):
return u'{}'.format(self.IngredientName)
In a function, i need serialize a JSON object from a query that returns from "Ingredient_step", but I need send the field "IngredientName", who comes from "Ingredient" table.
I try using "ingredient__IngredientName" but it fails.
Views.Py:
def IngredientByStep(request):
if request.is_ajax() and request.GET and 'id_Step' in request.GET:
if request.GET["id_Step"] != '':
IngStp = Ingredient_Step.objects.filter(Step =request.GET["id_Step"])
return JSONResponse(serializers.serialize('json', IngStp, fields=('pk','ingredient__IngredientName')))
How i can call extends field from a relation?
Thanks
This "feature" of Django (and many ORM's like SQLAlchemy) are called Lazy Loading, meaning data is only loaded from related models if you specifically ask for them. In this case, build your IngStp as a list of results, and make sure to access the property for each result before serializing.
Here's an example of how to do that: Django: Include related models in JSON string?

How to serialize Django queryset.values() into json?

I have a model that has many fields, however for this problem I only need 3 of those fields. When I try to serialize a .values set I get an exception:
'dict' object has no attribute '_meta'
This is my code:
queryset = myModel.objects.filter(foo_icontains=bar).values('f1', 'f2', 'f3')
serialized_q = serializers.serialize('json', queryset, ensure_ascii=False)
As other people have said, Django's serializers can't handle a ValuesQuerySet. However, you can serialize by using a standard json.dumps() and transforming your ValuesQuerySet to a list by using list(). If your set includes Django fields such as Decimals, you will need to pass in DjangoJSONEncoder. Thus:
import json
from django.core.serializers.json import DjangoJSONEncoder
queryset = myModel.objects.filter(foo_icontains=bar).values('f1', 'f2', 'f3')
serialized_q = json.dumps(list(queryset), cls=DjangoJSONEncoder)
Django serializers can only serialize queryset, values() does not return queryset rather ValuesQuerySet object. So, avoid using values(). Rather, specifiy the fields you wish to use in values(), in the serialize method as follows:
Look at this SO question for example
objectQuerySet = ConventionCard.objects.filter(ownerUser = user)
data = serializers.serialize('json', list(objectQuerySet), fields=('fileName','id'))
Instead of using objectQuerySet.values('fileName','id'), specify those fields using the fields parameter of serializers.serialize() as shown above.
Make list from objectQuerySet:
data_ready_for_json = list( ConventionCard.objects.filter(ownerUser = user).values('fileName','id') )
My solution, It's work fine
from django.core.serializers import serialize
import json
permission_list = Permission.objects.all().order_by('-id')
permission_serialize= json.loads(serialize('json', permission_list))
return JsonResponse({'data': permission_serialize})
Just cast to dict every item and create json with json.dumps:
json.dumps([dict(item) for item in SomeModel.objects.all().values('id', 'title')])
Try this:
queryset = myModel.objects.filter(foo_icontains=bar)
serialized_q = serializers.serialize(queryset, many = True)

Categories