I have a Django 1.9 project implementing small chat app. All messages from a certain recipient are grouped into dialogs, so the models are defined as follows:
class Dialog(models.Model):
# Some fields
class Message(models.Model):
dialog = models.ForeignKey(Dialog, ...)
text = models.TextField()
is_read = models.BooleanField(default = False)
My goal is to render a template with a table that renders dialogs. And for each dialog in the table, I need to see
the number of unread messages and
the text of the last message.
To illustrate, consider mock-data below:
Input:
id dialog_id message is_read
1 1 Hello, sir false
2 1 My name is true
3 1 Jack true
4 2 This site false
5 2 is perfect false
6 2 Cheers false
Desired output:
dialog_id last_message_in_dialog unread_messages_count
1 Jack 1
2 Cheers 3
In pure mysql, I would write a query like this:
select
a.dialog_id,
text as last_message_in_dialog,
(select count(*) from message
where dialog_id = a.dialog_id and is_read = false) as unread_messages_count
from message a
where id in (select max(id) from message group by dialog_id)
In Django terms, I have the code below:
max_id_qs = Message.objects.\
values('dialog__id').\
annotate(max_id = Max('id'),).values('max_id')
qs = Message.objects.filter(id__in = max_id_qs).\
values('dialog__id', 'text')
This code serves well to fetch the last message in each dialog. However, the problem is that I can't figure out how to implement the subquery (select count(*) from message where dialog_id = a.dialog_id and is_read = false) in Django. Maybe my total approach with max_id_qsis wrong, and there's more elegant and clear way to implement the query in Django ORM?
I've spent an entire day trying to solve this issue. help me please !
This will work :-
allDistinctIdWithNotReadMsg =
Message.objects.filter(is_read=False).values('id').annotate(the_count=Count('is_read',distinct('id')))
for ids in allDistinctIdWithNotReadMsg:
lastMsg = Message.objects.filter(dialog_id=ids['id']).order_by("-id")[0]
for msg in lastMsg:
print ids['id'] ,msg.message,ids['the_count']
Related
I have a table with a few thousand entries. And My purpose is to select all entries from all versions that correspond to a given one. And the resulted entries must correspond exactly to the given entry.
But somehow, the SQL query does not work. The original project uses Access 2007. But I have tried also in MySQL and no success
I put here the sql query, but I also made a SQL fiddle:
SELECT
idvalue,
idtag,
iddevice,
idversion,
idtext,
description,
idaccess,
defaultvalue,
minimumvalue,
acceptedvalue,
maximumvalue,
outofrangevalue,
iddatatypepn,
iddatatypeopc,
size,
idresolution,
idunit,
idaccuracy,
enumerationvalues,
comments,
remanentvolatile,
storedatpn,
storedatmain,
`generated`,
edittime
FROM
SomeValues
WHERE
idtag = 2 AND iddevice = 1
AND idtext = 433
AND description = 'Input voltage (AC)'
AND idaccess = 12
AND defaultvalue IS NULL
AND minimumvalue =0
AND acceptedvalue = 5300
AND maximumvalue = 10050
AND outofrangevalue = 11000
AND iddatatypepn = 2
AND iddatatypeopc = 19
AND size = 2
AND idresolution = 2
AND idunit = 1
AND idaccuracy = 2
AND enumerationvalues IS NULL
AND comments IS NULL
AND remanentvolatile IS NULL
AND storedatpn = FALSE
AND storedatmain = FALSE
AND `generated` = TRUE
Fiddle: here
Can you please explain what is wrong with the sql query?
The result should be those 3 entries from the fiddle table.
And yes, I must use all the conditions from the "Where" clause, since the entries can match 90% but also have small differences
You have problem in line:
AND description = 'Input voltage (AC)'
change it to:
AND description = '"Input voltage (AC)"'
and everything will works.
Problem lies in the fact that you searched for text Input voltage (AC) instead of "Input voltage (AC)" (how is stated in column description).
Newbie in sqlite, web2py. Am trying to copy sqlite db contents to controller for another function.
My codes are these:
db.py
auth.define_tables(username=False, signature=False)
auth.settings.registration_requires_verification = False
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
db.define_table('chat',
Field('me_from'),
Field('me_body', 'text'),
default:
#auth.requires_login()
def index():
chats.index(db)
body = db.chat.me_body()
rows = db(db.chat.me_body).select()#(orderby=~db.chat.me_body.created_on)
form1 = [body]
form5 = form1#.split()
name3 = ' '.join(form5)
I want t retrieve a string posted to db..
chat.id chat.me_from chat.me_body chat.me_html
1
2 maurice hi <div class="m...
3 maurice whats up <div class="m...
4 maurice where are you. <div class="m...
5 maurice 3i5ejp[eoityjdt <div class="m...
6 maurice how are you d...<div class="m...
7 maurice britam <div class="m...
From the table above, i want to retrieve from chat.me_body the posted words such as, 'hi', 'whats up', 'britam'... to default function. I instead keep getting the following errors:
If I use:
body = db.chat.me_body()
the error is:
TypeError: 'Field' object is not callable
If I use:
`body = db.chat.me_body
The error is:
TypeError: sequence item 0: expected string, Field found
If I use rows:
rows = db(db.chat.me_body).select()
and
form1 = [rows]
the error is:
name3 = ' '.join(form5)
TypeError: sequence item 0: expected string, Rows found
I I'll appreciate your help
The proper way to do a query to get records from the database is:
rows = db(db.chat).select(db.chat.me_body, db.chat.created_on,
orderby=~db.chat.created_on)
Note, db(db.chat) is shorthand for the query db(db.chat.id != None) (i.e., selection of all records in the table).
Then, to extract just the me_body field values into a list, you can use a list comprehension:
me_body_values = [r.me_body for r in rows]
Finally, you can join those values together:
name3 = ' '.join(me_body_values)
For a list query I want to show how many prices there are for a specific product on a specific site.
I have found a way to do this with RawSQL, something I had never ever had to do before. Am I overlooking something?
queryset = Price.objects.all()
site_annotations = {}
for site in Site.objects.all():
site_annotations['num_prices_{}'.format(site.name)] = RawSQL(
'SELECT COUNT(id) '
'FROM `product_siteprice` '
'WHERE `product_siteprice`.`price_id` = `product_price`.`id` '
'AND site_id=%s', [site.pk]
)
queryset = queryset.annotate(**site_annotations)
edit
My models look simplified like this:
class Site(Model):
name = models.CharField(_('display name'), max_length=50)
class Price(Model):
name = models.CharField()
class SitePrice(Model):
price = models.ForeignKey(Price)
site = models.ForeignKey(Site)
Now the table I want is:
Product | Nr of prices on Site A | Nr of prices on Site B |
--------|------------------------|------------------------|
Iphone | 6 | 3 |
Xperia | 42 | 66 |
And I want to sort and filter on the number of prices, so thats why I need the annotation.
NB The name Price is a bit misleading if you don't know the rest of context, in this context it can be seen more like a Product
From what I understand, you just need to filter the prices on the related site, then get the count of the number of objects.
Price.objects.filter(site_price__site_id=site.pk).count()
Although you may just want to remove the site price model and replace it with a many to many field
I think the query that you want would look something like this:
qs = SitePrice.objects.values('price_id', 'site_id').annotate(d_count=Count('id'))
And to get the table that you want, you’d format it into a dict with something like this:
from collections import defaultdict
values = defaultdict(dict)
for x in qs:
values[ x['price_id'] ][ x['site_id'] ] = x['d_count']
To print out this table, you would use:
price_ids = list(values.keys()) # you don’t need `list` for python 2
site_ids = set()
for x in values.values():
site_ids |= set(x.keys())
site_ids = list(site_ids)
site_ids.sort()
prices = dict(Price.objects.filter(id__in=price_ids).values_list('id', 'name'))
sites = dict(Site.objects.filter(id__in=site_ids).values_list('id', 'name'))
print(' ', end='') # for python 3
# print ' ', # for python 2
for x in site_ids:
print('%-8s ' % sites[x], end='')
print('')
for x, counts in values.items():
print('%-8s ' % prices[x], end='')
for site_id in site_ids:
d_count = counts.get(site_id, 0)
print('%-8s ' % d_count, end='')
print('')
I'm learning Flask Web Development book , and in Chapter 13 , it's about "comments for the blog post"
The route function of post is as below , the book said "when page = -1" , it will caculate how much comments totally , and to be divided "FLASKY_COMMENTS_PER_PAGE" , then it can know how many pages totally and decided which is the last page that you will go to.
But what confused me is that why the "(post.comments.count()" need to subtract 1 ???
i.e. If the comments quantity is 22 , then I added 1 comment
The caculation should be (23-1)//FLASKY_COMMENTS_PER_PAGE + 1 ???
I really don't know why I should subtract 1....
#main.route('/post/<int:id>')
def post(id):
post = Post.query.get_or_404(id)
form = CommentForm()
if form.validate_on_submit():
comment = Comment(body = form.body.data, post = post, author = current_user._get_current_object())
db.session.add(comment)
flash('Your comment has been published.')
return redirect(url_for('.post',id = post.id, page = -1))
page = request.args.get('page',1,type=int)
if page == -1:
page = (post.comments.count()-1)//current_app.config['FLASKY_COMMENTS_PER_PAGE']+1
pagination = post.comments.order_by(Comment.timestamp.asc()).paginate(
page,per_page = current_app.config['FLASKY_COMMENTS_PER_PAGE'],
error_out = False)
comments = pagination.items
return render_template('post.html',posts=[post],form = form,comments=comments,pagination = pagination)
Let's see this line:
page = (post.comments.count()-1)//current_app.config['FLASKY_COMMENTS_PER_PAGE']+1
let FLASKY_COMMENTS_PER_PAGE be 10. The page numbering starts from 1. Without the subtracting when there are 9 comments: 9//10 + 1 = 0 + 1 = 1 which is still good, but when you got 10 comments: 10//10 + 1 = 1 + 1 = 2. So you got 2 pages instead of 1. That's why you need to subtract 1 from the total comments.
I have the following code and would like to convert the request into a mysql query. Right now I achieve the desired result using a manual .select (array method) on the data. This should be possibile with a single query (correct me if I am wrong).
Current code:
def self.active_companies(zip_code = nil)
if !zip_code
query = Company.locatable.not_deleted
else
query = Company.locatable.not_deleted.where("zip_code = ?", zip_code)
end
query.select do |company|
company.company_active?
end
end
# Check if the company can be considered as active
def company_active?(min_orders = 5, last_order_days_ago = 15)
if orders.count >= min_orders &&
orders.last.created_at >= last_order_days_ago.days.ago &&
active
return true
else
return false
end
end
Explanation:
I want to find out which companies are active. We have a company model and an orders model.
Data:
Company:
active
orders (associated orders)
Orders:
created_at
I don't know if it is possible to make the company_active? predicate a single SQL query, but I can offer an alternative:
If you do:
query = Company.locatable.not_deleted.includes(:orders)
All of the relevant orders will be loaded into the memory for future processing.
This will eliminate all the queries except for 2:
One to get the companies, and one to get all their associated orders.