Create an instance that represents the average of multiple instances - python

I have a Review Model like the one defined below (I removed a bunch of the fields in REVIEW_FIELDS). I want to find the average of a subset of the attributes and populate a ModelForm with the computed information.
REVIEW_FIELDS = ['noise']
class Review(models.Model):
notes = models.TextField(null=True, blank=True)
CHOICES = ((1, u'Quiet'), (2, u'Kinda Quiet'), (3, u'Loud'))
noise = models.models.IntegerField('Noise Level', blank-True, null=True, choices=CHOICES)
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = REVIEW_FIELDS
I can easily add more fields to the model, and then add them to the REVIEW_FIELDS list. Then I can easily iterate over them in javascript, etc. In my view, I want to compute the average of a bunch of the integer fields and populate a ReviewForm with the attribute values. How can I do something like this?
stats = {}
for attr in REVIEW_FIELDS:
val = reviews.aggregate(Avg(attr)).values()[0]
if val:
stats[attr] = int(round(val,0))
r.attr = stats[attr]
r = Review()
f = ReviewForm(r)
How can I create a ReviewForm with the average values without hard-coding the attribute values? I'd like to be able to add the field, add the value to the list, and have it automatically added to the set of statistics computed.
If I'm doing something fundamentally wrong, please let me know. I'm relatively new to django, so I might be re-inventing functionality that already exists.

After looking at the docs, I pass a dictionary to the ReviewForm when instantiating it:
f = ReviewForm(stats)
It seems to work pretty well! If anyone has any suggestions on a better way to do this, I'm all ears!

Related

Build a list of values from queryset list (pk__in) in special order

i have a model with ratings, the results of a filter query must be in a special order for chartit (comparing ratings for trainee's) but I can't find the right way to do it. (ok I'm new to Django and python ;)
class Bewertung(models.Model):
auffassung = models.PositiveSmallIntegerField()
interesse = models.PositiveSmallIntegerField()
arbeitsabw = models.PositiveSmallIntegerField()
aufmerksamkeit = models.PositiveSmallIntegerField()
arbeitsgenauigkeit = models.PositiveSmallIntegerField()
verhalten = models.PositiveSmallIntegerField()
ausb_sach = models.PositiveSmallIntegerField(null=True, blank=True)
ausb_fuehr = models.PositiveSmallIntegerField(null=True, blank=True)
the query:
qs = Bewertung.objects.filter(pk__in=pk_list)
I want to compare the integer values in a multi bar chart e.g.
auffassung_from_pk(1,2,3) interesse_from_pk(1,2,3) .. n
but every try ends in a list with a lot of unordered values
(Auffassung_from_pk(1), interesse_from_pk(1), Auffassung_from_pk(2) ..)
I can't find a way to solve it nice and efficient in an python way.
so I need a little help, can you help?
#Sachin Kukreja correct, separate it and order it. so every field (e.g. auffassung must be one list with every result from the queryset.)
if I have 3 resulting query sets (pk_list=(1,2,3)) I need something like ((1,2,1),(2,3,3)...) ((auffassung),(interesse))
#Rajez there are no multiple filters
i set all my approach's to zero to start new. I have only this (in the Django shell)
for q in qs:
print(q.auffassung)
print(q.interesse)
i am really struggling at this at the moment
try it:
import itertools
qs = Bewertung.objects.filter(pk__in=pk_list)
values = qs.values_list('auffassung', 'interesse')
result = list(itertools.chain(*values))

Django: Filter a QuerySet and select results foreign key

In Django, I have two models:
class A(models.Model):
# lots of fields
class B(models.Model):
a = models.ForeignKey(A)
member = models.BooleanField()
I need to construct a query that filters B and selects all A, something like this:
result = B.objects.filter(member=True).a
Above example code will of course return an error QuerySet has no attribute 'a'
Expected result:
a QuerySet containing only A objects
Whats the best and fastest way to achieve the desired functionality?
I assume you are looking for something like
result = A.objects.filter(b__member=True)
An alternative to Andrey Zarubin's answer would be to iterate over the queryset you had and create a list of a objects.
b_objects = B.objects.filter(member=True)
a_objects = [result.a for result in b_objects]
Below code will not filter everything but it will filter all the values with respect to field, might be you are looking for same
B.objects.filter(member=True).filter(a__somefield='some value')

Count of ALL linked objects in django M2M object

A model is linked to several others using ManyToMany in the following manner:
class Tag(model.models):
attributes...
class A(model.models):
f = models.ManyToManyField(Tag)
class B(model.models):
f = models.ManyToManyField(Tag)
class C(model.models):
f = models.ManyToManyField(Tag)
And the objective is to get a count of ALL linked objects to Tag.
So something like count(A) + count(B) + count(C)
Is there a better way to do it than this:
count = 0
count += tag.a_set.count()
count += tag.b_set.count()
count += tag.c_set.count()
Also, what are the options for doing this programmatically when the linked models are unknown? I.e. We do not know the model name, so doing model_set is not possible.
A possible way:
# get count from all fields with '_set' at the end
linked_models = [
model_set
for model_set in dir(Tag)
if model_set.endswith('_set')
]
count = sum([
getattr(tag, model).count
for model in linked_models
])
Concerns:
performance on servers: this might take too much time to generate for each tag
there is a better way to do this: something hidden away in _meta perhaps that gets all linked objects together? I did not find anything (I'm sloppy!)

Iterating through an unlimited number of child objects in a Django queryset

I have a Django model that defines a list of categories. Each category can be a child of another category, and it is possible that depth of this list of categories could go on quite a bit.
models.py
class Category(models.Model):
code = UUIDField(unique=True, primary_key=True)
name = models.CharField(max_length=100, null=True, blank=True, unique=True)
parent_cat = models.ForeignKey('self', null=True, blank=True)
Consider for example, a Category for women's clothing. It may have something like the following:
Women's > Clothing > Dresses > Summer
That all works fine, but separately I want to build a function that can build a single list containing an extrapolated view of every category in the tree. To do that, I have written the following:
queryset = Category.objects.filter(parent_cat=kwargs['code'])
all_children = []
all_children.append(queryset.values())
for c in queryset:
children = Category.objects.filter(parent_cat=c.code)
if children:
all_children.append(children.values())
all_children.append(children)
I realise this code is probably quite sloppy, I'm still learning!
As you probable realise, this will only give me two levels of child objects.
My question is: What is the most efficient way that I can write this code so that it will find every possible category until it reaches the last object with no more children?
Thanks!!
you could try using recursion something along the lines of this:
Replace list with the apprpriate data type.
def parseQueryset(queryset)
for x in queryset:
if isinstancex(x, list):
parseQueryset(x)
else:
#do stuff
You are looking for https://en.wikipedia.org/wiki/Tree_traversal - and you can use django-mptt package: https://django-mptt.github.io/django-mptt/overview.html#what-is-modified-preorder-tree-traversal

Python + making a function more generic

I wanted some guidance if possible on how to make this more generic:
def get_industry_choices(self):
industries = Industry.objects.all().order_by('name')
ind_arr = [(ind.id, ind.name) for ind in industries]
return ind_arr
Basically this function will return choices as expected for the forms.ChoiceField. I need to do this in a few places, and wanted to make the function above more generic. I know how to get the industries = Industry.objects.all().order_by('name') to be generic, but the 2nd part is what I'm not sure about. When creating the tuples, it has (ind.id, ind.name). the ind.name can be any value depending on the model passed in (it may not always have name in the model).
I tried to read up on this in a few places including:
Passing functions with arguments to another function in Python?
The above resource shows how to do it using a function passed in, but that seems a bit overkill? If I have to pass a function as an argument anyway, whats the point of making it more generic with one more function?
[EDIT]
Basically I want to produce something similar to this:
TITLE_CHOICES=(
(1, 'Mr.'),
(2, 'Ms.'),
(3, 'Mrs.'),
(4, 'Dr.'),
(5, 'Prof.'),
(6, 'Rev.'),
(7, 'Other'),
)
So when doing forms.ChoiceField I can pass in TITLE_CHOICES for example as the possible choices. The first value is the value I get when the form is submitted, the second value is what the user sees on form. I want to be able to programmatically create this with any model, I pass in the model name and one field in the above example, name. I want to create the tuple such that it is (id, name). But name could be replaced with anything in a different model...
It is hard to tell from your question, but I think the bit you are missing is getattr(). For example
ind = something()
for field in ['id', 'name']:
print getattr(ind, field)
Actually, Django already has a shortcut for this: values_list.
Industry.objects.all().values_list('id', 'name')
or
fields = ['id', 'name']
Industry.objects.all().values_list(*fields)
Maybe this helps:
from some_app.models import SomeModel
def generate_choices(model, order=None *args):
choices = model.objects
if order:
choices = choices.order_by(order)
return choices.values_list('pk', *args)
class MyForm(forms.Form):
my_choice_field = CharField(max_length=1,
choices=generate_choices(SomeModel, 'name'))
other_choice_field = CharField(max_length=1,
choices=generate_choices(SomeModel, 'city', 'state'))

Categories