Django MySql - combining only() and distinct() - python

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')

Related

django-filter get queryset

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

Return all values of QuerySet and serialize into JSON

With this code all of the values are specified to return a QuerySet
import json
posts = (Post.objects.filter(owner=authenticated_user)
.values('id', 'title', 'summary'))
json_posts = json.dumps(list(posts))
Is there a way to avoid specifying all of the values for the QuerySet ('id', 'title', and 'summary')? For example
posts = (Post.objects.filter(owner=authenticated_user)
.values(ALL VALUES))
EDIT:
Ultimately the goal is to serialize the QuerySet into JSON. The following code raises an AttributeError
try:
obj = SystemOverview.objects.filter(serial=pk).values()
except SystemOverview.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
return Response(serializers.serialize("json", list(obj)))
#ERROR MESSAGE
#AttributeError: 'dict' object has no attribute '_meta'
What is the correct way of serializing a Django object model into JSON without listing all of its values?
As stated in the Django Documentation https://docs.djangoproject.com/en/1.10/ref/models/querysets/#values
The values() method takes optional positional arguments, *fields,
which specify field names to which the SELECT should be limited. If
you specify the fields, each dictionary will contain only the field
keys/values for the fields you specify. If you don’t specify the
fields, each dictionary will contain a key and value for every field
in the database table.
Simply use Post.objects.filter(owner=authenticated_user).values()
EDIT:
objs = SystemOverview.objects.filter(serial=pk).values()
if request.method == 'GET':
return Response(serializers.serialize("json", objs))

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.

Validating a Django model field based on another field's value?

I have a Django app with models accessible by both Django REST Framework and a regular form interface. The form interface has some validation checks before saving changes to the model, but not using any special Django framework, just a simple local change in the view.
I'd like to apply the same validation to forms and REST calls, so I want to move my validation into the model. I can see how to do that for simple cases using the validators field of the Field, but in one case I have a name/type/value model where the acceptable values for 'value' change depending on which type is selected. The validator doesn't get sent any information about the model that the field is in, so it doesn't have access to other fields.
How can I perform this validation, without having essentially the same code in a serializer for DRF and my POST view for the form?
I dug around codebase of drf a little bit. You can get values of all fields using following approach. Doing so, you can throw serialization error as
{'my_field':'error message} instead of {'non_field_error':'error message'}.
def validate_myfield(self, value):
data = self.get_initial() # data for all the fields
#do your validation
However, if you wish to do it for ListSerializer, i.e for serializer = serializer_class(many=True), this won't work. You will get list of empty values.
In that scenario, you could write your validations in def validate function and to avoid non_field_errors in your serialization error, you can raise ValidationError with error message as a dictionary instead of string.
def validate(self, data):
# do your validation
raise serializers.ValidationError({"your_field": "error_message"})
The validation per-field doesn't get sent any information about other fields, when it is defined like this:
def validate_myfield(self, value):
...
However, if you have a method defined like this:
def validate(self, data):
...
Then you get all the data in a dict, and you can do cross-field validation.
You can use the required package for your cross-field validation. It allows you to express your validation rules declaratively in python. You would have something like this with DRF:
class MySerializer(serializers.Serializer):
REQUIREMENTS = (
Requires("end_date", "start_date") +
Requires("end_date", R("end_date") > R("start_date")) +
Requires("end_date", R("end_date") < today.date() + one_year) +
Requires("start_date", R("start_date") < today.date() + one_year)
)
start_date = serializers.DateField(required=False, null=True, blank=True)
end_date = serializers.DateField(required=False, null=True, blank=True)
def validate(self, data):
self.REQUIREMENTS.validate(data) # handle validation error
You could put the REQUIREMENTS on your Model and have both your DRF and Django Form validate your data using it.
Here is a blog post explaining more

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?

Categories