how to get chart's data and labels - python

I would like to represent my data in a form of a chart,
but i am having a problem making the right queries to display the chart's labels and series ,
and basically i have a Book model , and a User model
and i want to display the number of books(series) that belongs to a particular user(labels) .
models.by
class Book(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=200)
template_tag
#register.simple_tag()
def chart_data():
users =
books =
return json.dumps({
'labels':[user.username for user in users],
'series':[[book.name for book in books]]
})

Something like this:
users = User.objects.all()
for user in users:
books = Book.objects.filter(user=user)

If I understand correctly, You need a json data which should have a label represents username and series representing book.name for that particular user.
Have you tried :
books = Book.objects.values('user__username', 'name').order_by('user__username', 'name')

If you want to do it for a particular user, then:
series = Books.objects.filter(user = "username").values("name")
This will produce a queryset:
<queryset: [{name: book1}, {name: book2}, ...]>
You can convert it to list like so:
list(series)
and then send it through json.dumps..
In the above case, you already know the user those books belongs too, but if you want specify it through the query, then:
series = Books.objects.filter(user = "username").values("name", "user__username")
This will produce something like this:
<queryset: [{name: book1, user: username1}, {name: book2, user: username1}, ...]>

Related

Django list of choices in MultipleChoiceField

I would like to display in a form every existing graph_id that exists in the GraphData model. like so:
GRAPHS_CHOICES = (GraphData.objects.all().values_list("graph_id", flat=True).distinct())
class GraphForm(forms.Form):
graphs = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=GRAPHS_CHOICES)
class GraphData(models.Model):
graph_id = models.CharField(max_length=128)
date = models.DateField(max_length=128)
The problem is that choices expects a tuple, and not a list of id's. How can I supply it with a list anyway?
you can change a QuerySet to tuple with this
query_tuple = [(q['id'], q['name']) for q in queryset]

Generate input fields based on a input and store it properly

I have a field called subjects that asks users how many subjects do they have and based on the number they input I want to generate the input fields of same number. And How and where do I store those inputs.
MODELS.PY
#this field will determine how many input fields to generate
subjects = models.IntegerField()
VIEWS.PY
def generate_forms(request):
no_of_fields = request.GET.get('subjects')
if no_of_fields:
#generate other inupts
#save it in the database
Besides generating the input, how do I save those data in the database.
Thanks in advance
If you use postgres you can use django postgres specefic models fields(Like ArrayField).django specefic fields documention
For another databases you can create model for your subjects and for each subject you can insert new data in Subject model.
class Subject(models.Model):
desc = models.CharField(max_length=50)
other_filed = models.ForeignKey(OtherModel)
def generate_forms(request):
other_field = 1
subjects = request.GET.get('subjects')
if subjects and subjects != '':
for subject in subjects:
Subject.objects.create(desc=subject, other_field=other_field)

Django: annotate Count with filter

I have "post" objects and a "post like" object with how many likes a post has received by which user:
class Post(models.Model):
text = models.CharField(max_length=500, default ='')
user = models.ForeignKey(User)
class PostLike(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
I can select how many likes a post has received like this:
Post.objects.all().annotate(likes=Count('postlike'))
This roughly translates to:
SELECT p.*,
Count(l.id) AS likes
FROM post p, postlike l
WHERE p.id = l.post_id
GROUP BY (p.id)
It works. Now, how I can filter the Count aggregation by the current user? I'd like to retrieve not all the likes of the post, but all the likes by the logged user. The resulting SQL should be like:
SELECT p.*,
(SELECT COUNT(*) FROM postlike WHERE postlike.user_id = 1 AND postlike.post_id = p.id) AS likes
FROM post p, postlike l
WHERE p.id = l.post_id
GROUP BY (p.id)
Do you know the Count has a filter argument?
Post.objects.annotate(
likes=Count('postlike', filter=Q(postlike__user=logged_in_user))
)
It's not exactly as clean, but you could use Case/When...
posts = Post.objects.all().annotate(likes=models.Count(
models.Case(
models.When(postlike__user_id=user.id, then=1),
default=0,
output_field=models.IntegerField(),
)
))
And of course, you can always drop down to .extra() or even raw SQL when there's something you can't express via the Django ORM.
Try to add filter first:
Post.objects.filter(postlike__user=request.user).annotate(likes=Count('postlike'))
From the docs:
The filter precedes the annotation, so the filter constrains the objects considered when calculating the annotation.

iterate over django form results (not in a template)

I am trying to iterate over form results and I can't help but think that I am re-inventing the wheel here.
filterlist = []
if request.POST:
form = FilterForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.iteritems():
filterlist.append(key)
filterlist.append(value)
This works, but seems very awkward and creates lots of other problems. For example the values come back with u' so I have to use value.encode("utf8") but then if a value is None it throws in error. So now I have to check if it is None, if not then encode. There has to be a better way.
EDIT: What I am trying to do.
I am trying to filter what is shown on a page. The problem I am running into is that if a value is empty (the user don't fill the box because they only want to filter against one object) then I get no results. For example a user wants to search for all books by the author name "Smith" but doesn't want to search against a genre.
results = Books.objects.filter(author=author, genre=genre)
The user would get no results because this is an AND search. But, if a user put in "Smith" for the author and "mystery" for the genre then it works exactly like I want it to, only giving results where both are true.
So, I am trying to eliminate the empty stuff by iterating over the form results. Like I said I am probably re-inventing the wheel here.
In Python 3 use:
for key, value in form.cleaned_data.items():
If the field names are the same in the model and the form, try this:
filter = {}
if request.method == 'POST':
form = FilterForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.iteritems():
if value:
filter[key] = value
results = Books.objects.filter(**filter)
Python is one of the few languages having named parameters. You can assemble a dict with the non-empty form fields and pass it to the filter method using the kwargs unpacking operator **.
For example:
kwargs = {"author": "Freud"}
results = Books.objects.filter(**kwargs)
Is the same as:
results = Books.objects.filter(author="Freud")
I think the problem is that by default the Model form is not valid if a form field does not have a value entered by the user, if you don`t require the field every time from the user you need to set the required field to false in the ModelForm class in forms.py as shown in the code below. Remember that the field is set false only in the model form not in the model itself
class myForm(forms.ModelForm):
myfield_id = forms.CharField(required=False)
myfield_foo = forms.CharField(required=False)
myfield_bar = forms.CharField(required=False)
myfield_name = forms.CharField(required=False)
class Meta:
model = myModel
exclude = ('myfield_ex','myfield_file')
fields = ['myfield_id','myfield_foo','myfield_bar','myfield_name',]
After you have the form entered by the user what you need is use the Q object which can be used to create complex queries as described in the manula page here
https://docs.djangoproject.com/en/1.7/topics/db/queries/#complex-lookups-with-q
A simple example code would look like
if form.is_valid():
qgroup = []
for key,value in form.cleaned_data.iteritems():
if value:
q_name = Q(**{"%s"%format(filterKey[key]) : value})
qgroup.append(q_name)
q = None
# can use the reduce as shown here qgroup = reduce(operator.or_, (Q(**{"{0}".format(filterKey[key]): value}) for (key,value) in form.cleaned_data.iteritems()))
for key,value in form.cleaned_data.iteritems():
if value:
q_name = Q(**{"%s"%format(filterKey[key]) : value})
qgroup.append(q_name)
for x in qgroup:
q &= x ### Or use the OR operator or
if q:
resultL = myModel.objects.filter(q).select_related()
The filterKey can look something on the lines of
filterKey = {'myfield_id' : "myfield_id",
'myfield_foo' : "myfield_foo__icontains",
'myfield_bar' : "myfield_bar__relative_field__icontains",
}

Querying a ManyToMany Field in a Django model

So I have these two models:
class Player(models.Model):
playerName = models.CharField(max_length= 50)
playerTeam = models.CharField(max_length=20)
class Role(models.Model):
roleName = models.CharField(max_length= 50)
players = models.ManyToManyField(Player)
Now, storing different players under one role was easy. My aim is to retrieve distinct 'playerTeam' under one role. To make it clear, I want the values of the different teams in string format. So, if two Player object is stored as:
p = Player(playerName='Zidane', playerTeam = 'Real Madrid')
p1 = Player(playerName='Laudrup', playerTeam = 'Barcelona')
and both are added to one Role object, say:
r = Role(roleName='playmaker')
r.save()
r.add(p)
r.add(p1)
r.save()
I want to write a query which will give me 'Real Madrid' and 'Barcelona' as results.
Writing the query for it is proving to be a challenge. Any help I can get?
What you need is:
r.players.values_list('playerTeam', flat=True)
Where r is the Role for which you want to get the teams.
If you want to get distinct teams, just put the result in a set().

Categories

Resources