How to convert export Django QuerySet to one dictonary? - django

How to convert export Django QuerySet to one dictonary?
I want to insert Django QuerySet as data_source into DataTable for Bokeh
queryset = Model.objects.all()
qs = queryset.values()
qs = dict(qs)
header = [field.verbose_name for field in Model._meta.get_fields()]
columns = [TableColumn(field=col, title=col) for col in header]
source = ColumnDataSource(qs)
data_table = DataTable(source=source, columns=columns)
script, div = components(data_table)
qs = dict(qs)
^^^^^^^^
ValueError: dictionary update sequence element #0 has length 11; 2 is required

The qs is not a dictionary, it is a sequence of object values (Queryset Values). Hence you can cast it as dictionary, but you can cast it as list (which will be list of dictionaries):
qs = list(qs)
It is not enough to load in your database. You need to build the dictionary from that list:
qs_dict = {}
for item in qs:
for field in Model._meta.get_fields():
qs_dict[field.verbose_name] = qs_dict.get(field.verbose_name, []).append(item[field.name])
source = ColumnDataSource(qs_dict)

Related

Django merge querysets in one page

In django rest framework i am using pagination of 20 on a model.
Now i want to make a queryset which takes 5 items which has the featured field as true.
The other 15 should be items which has the featured field as false.
Does anyone have an idea how to make this work?
permission_classes = [AllowAny]
serializer_class = JobSerializer
pagination_class = Pagination
order_types = {
1: 'job_order', #by randomized job order
2: '-created_date', #newest to oldest
3: 'created_date', #oldest to newest
4: 'name', #by name A -> Z,
5: '-name' #by name Z -> A,
}
def get_queryset(self):
requirements = self.request.query_params.getlist('requirements', None)
order_param = self.request.query_params.get('order_by', 1)
#make querysets
queryset_featured = Job.objects.all().filter(active=True, featured=True).order_by(self.order_types[int(order_param)])
queryset_non_featured = Job.objects.all().filter(active=True, featured=False).order_by(self.order_types[int(order_param)])
return queryset.distinct()
Use a union of two separate queries:
https://docs.djangoproject.com/en/3.1/ref/models/querysets/#union
This will allow you to make one ORM query for the featured items with [0:5], and then union to an ORM query for non-featured items with [0:15].
I haven't tested this, but here's an example with your code:
queryset_featured = Job.objects.all().filter(active=True, featured=True).order_by(self.order_types[int(order_param)])[0:5]
queryset_non_featured = Job.objects.all().filter(active=True, featured=False).order_by(self.order_types[int(order_param)])[0:15]
queryset_combined = queryset_featured.union(queryset_non_featured)
for row in queryset_combined:
print(row)

Extract values from Django <QuerySet> in Python 3

I have some python code:
UnitTestCollection.objects.filter(unit__type=unit_type)
which outputs data in format:
<QuerySet [<UnitTestCollection: VALUE1>, <UnitTestCollection: VALUE2>...
How can I extract a list of the values only i.e.
[VALUE1, VALUE2....]
Why not a simple list comprehension?
qs = UnitTestCollection.objects.filter(unit__type=unit_type)
my_values = [item.field_name for item in qs]
Or use values_list() to just fetch the specific field for each item directly in your queryset, with the advantage of lazy evaluation:
qs = UnitTestCollection.objects.filter(unit__type=unit_type)\
.values_list('field_name', flat=True)
values_list is better than a list comprehension because querysets are lazily evaluated. They won't be executed until you actually need them.
queryset = UnitTestCollection.objects.filter(unit__type=unit_type).values_list('<insert field>', flat=True)
This will return [field1, field2, field3...]
if you use .values('<insert field>') you'll get [{field: field value1}, {field: field value2}, {field: field value3}...]

Dynamically combine Q() - OR objects

I am trying to create a dynamic search in this ListView I have. My idea is to specify the fields and the type of search each time I try to inherit this view.
My problem is that every time I try to make a search, it works only on the first field of the tuple. In my example: requests__email is the first field, and when I print the object query_q after making a query for 'app', I get the following output:
(OR: (AND: ), ('requests__email__icontains', 'app'), (AND: ('requests__email__icontains', 'app'), ('status__icontains', 'app')), (AND: ('requests__email__icontains', 'app'), ('status__icontains', 'app'), ('license_type__name__icontains', 'app')))
I don't understand why, because I am using the operator I thought it would work |= in query_q |= Q(**query_kwargs). If I try to make a search based on the other attributes, status for example, the search doesn't work.
views.py
class DefaultListView(ListView):
searchable_fields = (
('requests__email', 'icontains'),
('status', 'icontains'),
('license_type__name', 'icontains'),
)
def get_queryset(self):
form = self.form_class(self.request.GET)
if form.is_valid():
if not self.searchable_fields:
raise AttributeError('searchable_fields has not been configured.')
term = form.cleaned_data['term']
query_kwargs = dict()
query_q = Q()
# Build a list of Q objects based on the searchable attribute
for field, search_type in self.searchable_fields:
query_kwargs["{0}__{1}".format(field, search_type)] = term
query_q |= Q(**query_kwargs)
ordering = self.get_ordering()
queryset = self.model.objects.filter(query_q)
if ordering:
return queryset.order_by(**ordering)
return queryset
return super(DefaultListView, self).get_queryset()
If you are wanting to build the query as X = Y OR W = Z it's because of
query_kwargs["{0}__{1}".format(field, search_type)] = term
You're adding more keys to query_kwargs with each iteration of the loop rather than re-creating the variable
Would suggest something like this
for field, search_type in self.searchable_fields:
query_q |= Q(**{"{0}__{1}".format(field, search_type): term})

Evaluate queryset and then call filter on it

Is there a way to evaluate a queryset and then call filter on it? I want access database only once in this example
example:
qs = Model.objects.all()
for element in array:
current = qs.filter(name=element)
The call qs.filter() here generates a new queryset which has nothing to do w/ qs.
Also, according to the doc, qs and current keep un-evaluated until certain operations.
You can filter in Python:
qs = Model.objects.all()
for element in array:
current = filter(lambda x: x.name==element, qs)
However, this is inefficient if your queryset and array are large. Alternatively, you can group your queryset by element:
from collections import defaultdict #
qs = Model.objects.all()
grouped = defaultdict(list)
for obj in qs:
grouped[obj.name].append(obj)
for element in array:
current = grouped[element]
If array contains only a small subset of name values, it might make sense to limit the queryset:
qs = Model.objects.filter(name__in=array)
If you would like to build your query with one hit to the database, you are going to need to use a Q object:
from django.db.models import Q
q = Q()
for element in array:
q &= Q(name=element)
qs = Model.objects.filter(q)

update form - using formsets - initial values unknown until runtime

I'm new to python and Django and have a simple question on how to update f form that has multiple fields of same type: I have been trying to do this with formsets:
I have a simple model to store categories:
class Category(BaseModel):
categoryText = db.StringProperty()
parentCat = db.IntegerProperty()
I want to create a form that would display all available categories in input fields so they could all be edited:
using formsets to display mulitple rows of the same type:
EDIT:
figured it out:
I had to create a list of dictionary items
categories = Category.objects.all()
initialStuff = []
oneFormV={}
for cat in categories:
oneFormV.clear()
oneFormV["categoryText"]=cat.categoryText
oneFormV["parentCat"]=str(cat.parentCat)
oneFormV["catID"]=str(cat.key().id())
initialStuff.append(oneFormV.copy())
def showCategories(request):
if request.POST:
# code to update db
else:
categories = Category.objects.all()
initialStuff = []
for cat in categories:
initialStuff += "'categoryText':u'" + cat.categoryText +"'," + "'parentCat':u'" + str(cat.parentCat) +"'," + "'catID':u'" + str(cat.key().id()) + "'"
initialStuff = initialStuff [:-1] # remove last comma
CategoryFormSet = formset_factory(CategoryForm,extra=categories.count())
formset = CategoryFormSet(initial= initialStuff )
return render_to_response('adminCategories.html', {'formset': formset})
I am having problem with populating the initial data. When I generate in a loop it gives me errors :
class CategoryForm(forms.Form):
categoryText = forms.CharField()
parentCat = forms.CharField()
catID = forms.CharField()
I am assuming I need to store the ID for the fields to update them!
Finally my question:
1) Am I doing this right or is there an easier way to accomplish this?
2) my problem has been passing initial values to a formset with initial values unknown until run time.
3) should I forget about formsets and do this by adding fields to the form with init?
4) what is the correct way of initializing form fields in a formset?
AM
initialStuff must be list of dicts, not list of strings:
for cat in categories:
initialStuff.append( { categoryText: cat.categoryText,
...
}
)
So, don't remove the last comma.
If you use the operation += for list and str you get a list of strings (each str has length 1).
Please view the next: http://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-initial-data-with-a-formset