Querying multiple tables in Django - python

I'm beginner in Django and Python, I started developing survey app. It's based on https://github.com/jessykate/django-survey
I added few features, but I'm having problem with results page, to be more precisely how to
get data to present them. Here's what models with most important fields look like:
class Survey(models.Model):
name = models.CharField(max_length=250)
class Question(models.Model):
text = models.TextField()
survey = models.ForeignKey(Survey)
choices = models.TextField()
class Response(models.Model):
survey = models.ForeignKey(Survey)
class AnswerBase(models.Model):
question = models.ForeignKey(Question)
response = models.ForeignKey(Response)
class AnswerText(AnswerBase):
body = models.TextField(blank=True, null=True)
class AnswerRadio(AnswerBase):
body = models.TextField(blank=True, null=True)
and few more Answer..
I think data in this format would be good to process later in js and display as bar char:
results = [{'some_question_text':
[{'answer':'answer1','count': 11},{'answer':'answer2','count': 6}, ..]}
,..]
I could't came up how to do it in django way, so i tried in sql. Problem is, it works only with one answer type, when I add another condition like 'or ab.id==polls_answerselect.answerbase_ptr_id' query returns strange results.
Here's what I've done:
cursor = connection.cursor()
cursor.execute("select q.text as qtext, ar.body as ans, ab.id as Aid, q.id as Qid, count(ar.body) as count \
from polls_answerbase ab, polls_answerradio ar, polls_question q, polls_survey s \
where ab.id==ar.answerbase_ptr_id \
and ab.question_id==q.id \
and s.id==q.survey_id \
group by ar.body")
rows = dictfetchall(cursor)
result = {}
for r in rows:
res[r['qtext']] = []
res[r['qtext']].append({'ans': r['ans'], 'count': r['count']})
What is better and correct way to solve my problem?

It looks like what you want here is a question list filtered by survey, and you want it in json format.
Take a look at http://django-rest-framework.org/ It comes with a set of predefined class based views that support multiple response formats, json being one of them. The tutorial on that site walks you through setting it up, and uses simple tests along the way to verify you're doing it right. You can do something similar for your models.
I'm a Python/Django beginner as well and found it very easy to pick up.

Related

Excluding existed users in the ManyToManyField

I am building a small BlogApp and I build a feature of adding favorite users. User can search and add the user in his favorite users list
I am now building a feature if searched user is already in another's users favorite user list then exclude the user from the result
For example :- If user_1 added user_50 in his favorite user's list. and then if user_2 searched user_50 then it will not show in the search list.
BUT when i try to exclude then it is not excluding.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,unique=True)
full_name = models.CharField(max_length=100,default='')
friends = models.ManyToManyField("Profile",blank=True)
email = models.EmailField(max_length=60,default='')
class FavouriteUsers(models.Model):
adder = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
favouriteUser = models.ManyToManyField(User, related_name='favouriteUser', blank=True)
views.py
def search_users_favourite(request):
q = request.GET.get('q')
exclude_this = FavouriteUsers.objects.filter(favouriteUser=request.user)
results = Profile.objects.filter(user__username__icontains=q).exclude(exclude_this)
serialized_results = []
for result in results:
serialized_results.append({
'id': result.id,
'username': result.user.username,
})
return JsonResponse({'results': serialized_results})
BUT this is showing :-
TypeError: Cannot filter against a non-conditional expression.
I have tried many times but it is still that error.
Any help would be Appreciated.
Thank You in Advance.
Try this query:
Profile.objects.filter(user__username__icontains=q, user__favouriteUser__isnull=True)
This will exclude all profiles that are already mapped in FavouriteUsers (already has been a favorite)
I think you should be doing it this way
exclude_this = FavouriteUsers.objects.filter(favouriteUser=request.user).values_list('favouriteUser__username',flat=True)
results = Profile.objects.filter(user__username__icontains=q).exclude(user__username__in=exclude_this) here, i assume you want to exclude usernames matching the entire name.
For a better answer, please attach the log of the error.
I spent hours tearing my hair out over this issue, so I wanted to post a quick response here on what is actually causing this exception:
The problem is this (pseudo code):
query = Model.objects.filter(something=value)
result = Model.objects.filter(query).first()
This won't work (apparently). Django hates it big time.
The problem is that you can't pass a QuerySet to filter or exclude.
Instead, use your QuerySet directly:
query = Model.objects.filter(something=value)
result = query.first()

Django How to update model object fields from external api data

I have a script which runs on a scheduler to get data from an api which I then intend to use this data to update the current database model information.
My model ShowInfo within main/models.py:
from django.contrib.auth.models import User
class ShowInfo(models.Model):
title = models.CharField(max_length=50)
latest_ep_num = models.FloatField()
ld = models.BooleanField()
sd = models.BooleanField()
hd = models.BooleanField()
fhd = models.BooleanField()
following = models.ManyToManyField(User, related_name = 'following', blank=True)
I managed to isolate the issue to this section of the script which runs but inserts duplicate shows with the same titles into the database:
else: #test if api fails
for t in real_title:
if t in data_title: #testing if the titles in the database and from the api match
a = ShowInfo.objects.get(title=t)
id = a.id
b = next(item for item in show_list if item["title"] == t)
a1 = ShowInfo(id = id, title = b["title"], latest_ep_num=b["latest_ep_num"], ld=b["ld"], sd=b["sd"],hd=b["hd"],fhd=b["fhd"])
a1.save()
Some additional info about the lists (where show_list is a list of dictionaries gotten from an api):
database = ShowInfo.objects.values()
real_title = []
data_title = []
for show in show_list:
real_title.append(show["title"])
for data in database:
data_title.append(data["title"])
When the script runs I notice from browsing my database with DB Browser for SQLite that the objects were being inserted and not updating as i intended.
The script is supposed to catch shows with the same title from the api and the database and to update any changed information. Does anyone have any idea what is wrong with my save() method?
After a day of trial and error and scrounging around the internet I finally found a solution that worked for me.
For anyone interested, this is the solution that I found from another user on Stack which utilized overriding the internal save method to force an update and not insert if the current object with the same field is already in the DB.
Other methods such as doing force_update=True or update_or_create() did not work in my case.

Sort Django query result by number of matches

In my Django app, I have Blogs and BlogPosts.
Their models are basically this:
class Blog(models.Model):
name = models.CharField(Entry)
details = models.TextField()
...
class BlogPost(models.Model):
blog = models.ForeignKey(Blog)
title = models.CharField()
...
Given a list of blog names, I would like to return all of the BlogPosts that appear in at least one of the given blogs.
I've figured out how to do this using Q objects. I've created a query like this:
# Return blogs that appear in either nameOfBlog1 or nameOfBlog2
q1 = Q(blog__name = nameOfBlog1)
q2 = Q(blog__name = nameOfBlog2)
Blog.objects.filter(q1 | q2)
This works.
However, I would like to receive the results in the order of the BlogPosts that match the highest number of Blogs. So for example, the BlogPosts that appear in all of the Blogs I'm searching against, should appear first in the list, while BlogPosts that only appear in one of the Blogs should appear at the end.
Is there any way to do this in Django?
try this:
BlogPost.objects.filter(q1 | q2).annotate(blog_times=Count('id')).order_by('blog_times')

How to delete a many to many object without deleting all objects within the relationship?

In models.py I have...
class Siteinfo(models.Model):
url = models.CharField(max_length=100)
description = models.TextField()
class Makesite(models.Model):
sitename = models.CharField(max_length=100, unique = True)
siteinfo = models.ManyToManyField(Siteinfo)
ref_id = models.ManyToManyField(RefID)
def __unicode__(self):
return u'%s' %(self.sitename)
I'm trying to delete a instance of description and replace it with another instance and still have it be associated with the same url and still be the many to many object under say. Group on.
So group1 is the site name. to create the relation I have
url = request.POST['url']
description = request.POST['description']
datsite = Makesite.objects.get(sitename=site)
datsite.siteinfo.add(Siteinfo.objects.create(url=url,description=description))
But then when I try to delete and replace the description with this bit of code it also deletes the url.
name = Makesite.objects.get(sitename=site).siteinfo.values_list('description',flat=True)[0]
Makesite.objects.get(sitename=site).siteinfo.get(description=name).delete()
I guess I could try to write some code that could get around this problem but I'd rather find a way to just delete one and add another instance in its place.
Just to be picky, you should be using forms for processing user input.
It sounds like you want to be updating an instance, not deleting and adding one nearly exactly the same.
site_info = Makesite.objects.get(sitename=site).siteinfo.get(description=name)
site_info.description = "new description"
site_info.save()
Or, more simply:
site_info = Siteinfo.objects.get(makesite__sitename=site, description=name) # only 1 query
site_info.description = "new description"
site_info.save()

Python Serialization (to JSON) issue

I'm a bit of a newbie in Python, so go easy on me. I'm writing an AJAX handler in Django. Everything's been pretty straight-forward on this until now. I've been banging my head against this bit for the better part of a day. I'd like to return a JSON string that contains a dict that contains a queryset:
#
# models.py
#
class Project(models.Model):
unique_name = models.CharField(max_length=32, unique=True)
title = models.CharField(max_length=255, blank=True)
description = models.TextField('project description', blank=True)
project_date = models.DateField('Project completion date')
published = models.BooleanField()
class ProjectImage(models.Model):
project = models.ForeignKey('Project', related_name='images')
image = models.ImageField(upload_to=get_image_path)
title = models.CharField(max_length=255)
sort_metric = models.IntegerField()
#
# views.py
#
...
projects = Project.Project.objects.filter(published=True)
...
response_dict({
'success' : True,
'maxGroups' : 5, # the result of some analysis on the projects queryset
'projects' : projects
});
# This one works if I remove 'projects' from the dict
# response = json.dumps( response_dict )
# This one works only on projects
# response = serializers.serialize( 'json', response_dict, relations=('images') )
return HttpResponse( response, mimetype='application/javascript' )
I've commented out the two serialization lines, because:
The first one seems to only work with 'simple' dicts and since projects is included in my dict, it fails with [<Project: Project object>] is not JSON serializable
The second one seems to only work with querysets/models and since the 'outer' part of my dict is non-model, it complains that 'str' object has no attribute '_meta'. Note that I am using the wadofstuff serializer with the understanding that it would resolve the OneToMany relationship as defined in my model. But even when I get this working by only serializing projects, I do not have any of my ProjectImages in the output.
QUESTION 1: What is the best way to serialize the whole response_dict? Surely, I'm not the first person to want to do this, right?
QUESTION 2: Why am I unable to get the ManyToOne relationship to work?
Many thanks for your help.
UPDATE: Just found this one: Django JSON Serialization with Mixed Django models and a Dictionary and it looked promising, but I get 'QuerySet' object has no attribute '_meta' =(
You can't serialize a python object like that. There is a section in the django documentation on what to do.
https://docs.djangoproject.com/en/dev/topics/serialization/#id2
Here is the key part to look at:
json_serializer.serialize(queryset, ensure_ascii=False, stream=response)

Categories

Resources