Currently I am filtering empty fields in all entries of the queryset like this:
data_qs = DataValue.objects.filter(study_id=study.id) #queryset
opts = DataValue._meta # get meta info from DataValue model
field_names = list([field.name for field in opts.fields]) # DataValue fields in a list
field_not_empty = list() # list of empty fields
for field in field_names:
for entry in data_qs.values(field):
if entry.get(field) is not None:
field_not_empty.append(field)
break
It works but not sure if it is an appropriate solution....
Does anyone know how to filter empty values in all the queryset? The table have more than 30 fields, so depending on the study ID some querysets may contain the field1 all empty, other study ID may contain all the field2 empty.
Does the Django ORM provide an easy an clean solution to do this?
Thanks in advance
To check if some value in a QuerySet is empty, say the values name is "title".
This will exclude all empty fields
DataValue.objects.filter(study_id=study.id).exclude(title__exact='')
If you only want the empty fields, just filter it
DataValue.objects.filter(study_id=study.id, title__exact='')
Hope it helped.
Related
I have a programme where users should be able to filter different types of technologies by their attributes. My question is, how would I filter the technologies when there's potential conflicts and empty values in the parameters I use to filter?
Forms.py:
class FilterDataForm(forms.ModelForm):
ASSESSMENT = (('', ''),('Yes', 'Yes'),('No', 'No'),)
q01_suitability_for_task_x = forms.ChoiceField(label='Is the technology suitable for x?',
choices=ASSESSMENT, help_text='Please select yes or no', required=False,)
q02_suitability_for_environment_y = forms.ChoiceField(label='Is the technology suitable for environment Y?',
choices=ASSESSMENT, help_text='Please select yes or no', required=False)
There are many fields in my model like the ones above.
views.py
class TechListView(ListView):
model = MiningTech
def get_queryset(self):
q1 = self.request.GET.get('q01_suitability_for_task_x', '')
q2 = self.request.GET.get('q02_suitability_for_environment_y', '')
object_list = MiningTech.objects.filter(q01_suitability_for_task_x=q1).filter(
q02_suitability_for_environment_y=q2)
return object_list
The difficulty is that not all technology db entries will have data. So in my current setup there's times where I will filter out objects that have one attribute but not another.
For instance if my db has:
pk1: q01_suitability_for_task_x=Yes; q02_suitability_for_environment_y=Yes;
pk2: q01_suitability_for_task_x=Yes; q02_suitability_for_environment_y='';
In the form, if I don't select any value for q01_suitability_for_task_x, and select Yes for q02_suitability_for_environment_y, I get nothing back in the queryset because there are no q01_suitability_for_task_x empty fields.
Any help would be appreciated. I'm also ok with restructuring everything if need be.
The problem is that your self.request.GET.get(...) code defaults to an empty string if there is no value found, so your model .filter() is looking for matches where the string is ''.
I would restructure the first part of get_queryset() to build a dictionary that can be unpacked into your filter. If the value doesn't exist then it doesn't get added to the filter dictionary:
filters = {}
q1 = self.request.GET.get('q01_suitability_for_task_x', None)
q2 = self.request.GET.get('q02_suitability_for_environment_y', None)
if q1 is not None:
filters['q01_suitability_for_task_x'] = q1
... etc ...
object_list = MiningTech.objects.filter(**filters)
If you have a lot of q1, q2, etc. items then consider putting them in a list, looping through and inserting into the dictionary if .get(...) returns anything.
Edit: Because there are indeed a lot possible filters, the final solution looks as follows:
def get_queryset(self):
filters = {}
for key, value in self.request.GET.items():
if value != '':
filters[key] = value
object_list = Tech.objects.filter(**filters)
Suppose I have a Person model that has a first name field and a last name field. There will be many people who have the same first name. I want to write a TastyPie resource that allows me to get a list of the unique first names (without duplicates).
Using the Django model directly, you can do this easily by saying something like Person.objects.values("first_name").distinct(). How do I achieve the same thing with TastyPie?
Update
I've adapted the apply_filters method linked below to use the values before making the distinct call.
def apply_filters(self, request, applicable_filters):
qs = self.get_object_list(request).filter(**applicable_filters)
values = request.GET.get('values', '').split(',')
if values:
qs = qs.values(*values)
distinct = request.GET.get('distinct', False) == 'True'
if distinct:
qs = qs.distinct()
return qs
values returns dictionaries instead of model objects, so I don't think you need to override alter_list_data_to_serialize.
Original response
There is a nice solution to the distinct part of the problem here involving a light override of apply_filters.
I'm surprised I'm not seeing a slick way to filter which fields are returned, but you could implement that by overriding alter_list_data_to_serialize and deleting unwanted fields off the objects just before serialization.
def alter_list_data_to_serialize(self, request, data):
data = super(PersonResource, self).alter_list_data_to_serialize(request, data)
fields = request.GET.get('fields', None)
if fields is not None:
fields = fields.split(',')
# Data might be a bundle here. If so, operate on data.objects instead.
data = [
dict((k,v) for k,v in d.items() if k in fields)
for d in data
]
return data
Combine those two to use something like /api/v1/person/?distinct=True&values=first_name to get what you're after. That would work generally and would still work with additional filtering (&last_name=Jones).
Is there a way of having only a filtered part of a model as a SeachQuerySet?
Something like:
query = SearchQuerySet().models(Entry.filter(categories__name='something'))
instead of
query = SearchQuerySet().models(Entry)
The field I want to filter by is a manytomany field and non indexed.
The search index doesn't store any relations, it is therefore 'flat'. You can only add your categories' IDs to the index for Entry (note that you have to use a prepare_-method for this):
class EntryIndex(indexes.SearchIndex, indexes.Indexable):
# your other fields
categories = MultiValueField()
def prepare_categories(self, obj):
return [category.pk for category in obj.categories.all()]
The you can do something like:
category = Category.objects.get(name='something')
sqs = SearchQuerySet().models(Entry).filter(categories=category.pk)
I need to re-order a Django queryset, because I want to put None values at the bottom of an ORDER BY DESC query on a FloatField.
Unfortunately, I'm struggling to find an elegant way to manipulate a Django queryset. Here's what I have so far:
cities = City.objects.filter(country__id=country.id).order_by('value')
if cities.count() > 1:
cities_sorted = cities
del manors_sorted[:]
for city in cities:
cities_sorted += city
# Add code to
cities = cities_sorted
Currently, this fails with 'QuerySet' object does not support item deletion.
Any idea how I can copy and re-order this QuerySet to put None items last?
The queryset will be evaluated to a list, if you eg. call list() on it:
cities_sorted = list(cities)
I'm trying to write a method like the below where a list of fields (a subset of all the fields) is passed in as a parameter and has their column values set to null. I would be happy of I could get a method with just the fields as a parameter like below, but having the model as a parameter would be even better.
from my_project.my_app.models import MyModel
def nullify_columns (self, null_fields):
field_names = MyModel._meta.get_all_field_names()
for field in field_names:
if field in null_fields:
# The below line does not work because I'm not sure how to
# dynamically assign the field name.
MyModel.objects.all().update( (MyModel.get_field(field).column) = None)
Right now I have something like
if 'column1' in list_of_fields:
MyModel.objects.all().update(column1 = None)
if 'column2' in list_of_fields:
MyModel.objects.all().update(column2 = None)
etc. which is horrible, but works.
It's in the tutorial:
MyModel.objects.all().update(**dict.fromkeys(null_fields))