In Django I builded a model based on view and in admin account i see there is added values that are not present in postgresql database.
These are ordered values in db view:
but in admin values looks like laged by 1 day:
Model in django looks like this:
class VBalance(models.Model):
id = models.IntegerField(primary_key=True)
date = models.DateField()
balance = models.DecimalField(max_digits=14, decimal_places=2)
class Meta:
managed = False # Created from a view. Don't remove.
db_table = 'v_balance'
def __str__(self) -> str:
# return "Balance: " + "{:.2f}".format(self.balance) + " on: " + self.date.strftime("%m/%d/%Y")
return "Balance: " + str(self.balance) + " on: " + self.date.strftime("%m/%d/%Y")
Any ideas how to fix this?
EDIT - db screeens with data:
View v_balance is builded like this:
CREATE OR REPLACE VIEW rap.v_balance
AS SELECT row_number() OVER () AS id,
balance_avg.date,
avg(balance_avg.balance) AS balance
FROM ( SELECT balance.date + 1 AS date,
sum(balance.amount) OVER (ORDER BY balance.date) AS balance
FROM ( SELECT COALESCE(b.date, dt.dt::date) AS date,
b.amount
FROM generate_series('2021-08-24 00:00:00+02'::timestamp with time zone, CURRENT_DATE::timestamp with time zone, '1 day'::interval) dt(dt)
LEFT JOIN import.balance b ON date(dt.dt) = b.date
UNION
SELECT transactions.date,
transactions.amount
FROM ( SELECT date(transactions_xtb.close_time) AS date,
sum(transactions_xtb.net_profit) AS amount
FROM import.transactions_xtb
GROUP BY (date(transactions_xtb.close_time))
ORDER BY (date(transactions_xtb.close_time))) transactions
ORDER BY 1) balance
ORDER BY (balance.date + 1)) balance_avg
GROUP BY balance_avg.date;
It's based on two tables: balance and transactions.
Table balance have only one row and it's not null:
Table transactions also dont have null values:
What's more it's look like django lag date becuase in my view recent date is: 2022-01-02 but in Django is: 2022-01-01.
So dates are laged but values are not.
Related
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
limit = models.PositiveIntegerField(default='255')
date = models.DateField()
Hello .
This is my model.I want to fetch the data for "limit" and "where id = 5" for example. How can I do that ? I want to use it as Integer. not Queryset.
If there is only one instance with id = 5 (it should be), then you can get value of limit using:
YourModel.objects.get(id=5).limit
You can read more about making queries here: https://docs.djangoproject.com/en/4.0/ref/models/querysets/
I'm try to select two table that have some common field. in raw MySQL query, i can write this:
SELECT t1.id, t1.username, t1.date FROM table1 as 't1' UNION SELECT t2.id, "const_txt", t2.date FROM table2 as 't2'
In that query ,the username field is not in table2 and I set const_txt instead.
So, in peewee, i want to union two table that have the same above situation.
class PeeweeBaseModel(Model):
class Meta:
database = my_db
class Table1(PeeweeBaseModel):
id = PrimaryKeyField()
username = CharField(255)
date = DateTimeField()
#other fields ...
class Table2(PeeweeBaseModel):
id = PrimaryKeyField()
date = DateTimeField()
#other fields ...
and then , union two model. something like this:
u = (
Table1(
Table1.id,
Table1.username,
Table1.date
).select()
|
Table2(
Table2.id,
"const_text_instead_real_field_value",
Table2.date
).select()
).select().execute()
But the const_text is not accepted by a field and ignore in result query.
the question is: How can I define a field that does not exist in my table and set it manually in query?
(And I prefer not using SQL() function.)
thanks.
you can use SQL() in SELECT statement.
u = (
Table1(
Table1.id,
Table1.username,
Table1.date
).select()
|
Table2(
Table2.id,
SQL(" '' AS username "),
Table2.date
).select()
).select().execute()
I have a table of posts. I display the list of posts paginated organized by time descending with each page limited to 20 rows. How do I figure out what page a specific row is by id is on so I can link to that specific page.
Table post
CREATE TABLE post
(
id serial NOT NULL,
text character varying(1000),
created_date timestamp without time zone,
CONSTRAINT post_pkey PRIMARY KEY (id)
)
Current
select * from post order by created_date desc limit 20 offset 0
What page is id X on? My theory is I can return the row number the id is on when you select by the specific 'order by' but I'm not sure if that's right or how to do that.
I suggest the window function row_number() in a subquery:
SELECT rn / 20 + 1 AS page -- 20 rows per page
FROM (
SELECT id, row_number() OVER (ORDER BY created_date DESC) AS rn
FROM post
) sub
WHERE id = 123;
The usual disclaimer: page numbers can change if underlying data changes (concurrently).
If you want a single link and if the created_date is always the inserting current_timestamp then it can be done counting the serial id
select count(*) / 20 + 1 as page
from post
where id >= %(id)s
To make it easier to always have the current_timestamp as the created_date make it the default
created_date timestamp default current_timestamp
It is possible to make it a constraint
created_date timestamp default current_timestamp check(created_date = current_timestamp)
If you need a list of links pass the ids as a Python list to the query
select *
from (
select id, count(*) over(order by id desc) / 20 + 1 as page
from post
where
id >= (
select id
from unnest(%(ids_list)s) s
order by id
limit 1
)
) s
where id = any (%(ids_list))s
In this last query count is a running total.
SQL Fiddle
Suppose I have two models:
class User(models.Model):
name = CharField(max_length=42)
class Action(models.Model):
user = models.ForeignKey(User)
timestamp = models.DateTimeField(auto_now_add=True)
How can I find all users who have more actions on weekends (sunday and saturday) than on other days of week and vice versa?
Edit: I don't need to check this condition for one user, that would be easy. I need to select all users who have one of these conditions hold true.
This can be done in one query with the extra method, passing a custom statement in the WHERE clause. This MySQL example selects all users where the number of actions during the weekend is less than or equal to the number of actions on other days:
f = {
'user_table': User._meta.db_table,
'action_table': Action._meta.db_table,
'user_id': User._meta.pk.get_attname_column()[1],
'user_fk': Action._meta.get_field('user').get_attname_column()[1],
'timestamp': Action._meta.get_field('timestamp').get_attname_column()[1],
}
query = "(SELECT COUNT(*) FROM %(action_table)s \
WHERE %(action_table)s.%(user_fk)s = %(user_table)s.%(user_id)s \
AND DAYOFWEEK(%(action_table)s.%(timestamp)s IN (1,7)) \
<= (SELECT COUNT(*) FROM %(action_table)s \
WHERE %(action_table)s.%(user_fk)s = %(user_table)s.%(user_id)s \
AND DAYOFWEEK(%(action_table)s.%(timestamp)s) NOT IN (1,7))" % f
users = User.objects.extra(where=[query]))
The syntax might be slightly different for backends other than MySQL. You should of course alter the table- and columnnames for your situation.
how can i have a subquery in django's queryset? for example if i have:
select name, age from person, employee where person.id = employee.id and
employee.id in (select id from employee where employee.company = 'Private')
this is what i have done yet.
Person.objects.value('name', 'age')
Employee.objects.filter(company='Private')
but it not working because it returns two output...
as mentioned by ypercube your use case doesn't require subquery.
but anyway since many people land into this page to learn how to do sub-query here is how its done.
employee_query = Employee.objects.filter(company='Private').only('id').all()
Person.objects.value('name', 'age').filter(id__in=employee_query)
Source:
http://mattrobenolt.com/the-django-orm-and-subqueries/
ids = Employee.objects.filter(company='Private').values_list('id', flat=True)
Person.objects.filter(id__in=ids).values('name', 'age')
The correct answer on your question is here https://docs.djangoproject.com/en/2.1/ref/models/expressions/#subquery-expressions
As an example:
>>> from django.db.models import OuterRef, Subquery
>>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
>>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))
You can create subqueries in Django by using an unevaluated queryset to filter your main queryset. In your case, it would look something like this:
employee_query = Employee.objects.filter(company='Private')
people = Person.objects.filter(employee__in=employee_query)
I'm assuming that you have a reverse relationship from Person to Employee named employee. I found it helpful to look at the SQL query generated by a queryset when I was trying to understand how the filters work.
print people.query
As others have said, you don't really need a subquery for your example. You could just join to the employee table:
people2 = Person.objects.filter(employee__company='Private')
hero_qs = Hero.objects.filter(category=OuterRef("pk")).order_by("-benevolence_factor")
Category.objects.all().annotate(most_benevolent_hero=Subquery(hero_qs.values('name')[:1]))
the generated sql
SELECT "entities_category"."id",
"entities_category"."name",
(SELECT U0."name"
FROM "entities_hero" U0
WHERE U0."category_id" = ("entities_category"."id")
ORDER BY U0."benevolence_factor" DESC
LIMIT 1) AS "most_benevolent_hero"
FROM "entities_category"
For more details, see this article.
Take good care with onlyif your subqueries don't select the primary key.
Example:
class Customer:
pass
class Order:
customer: Customer
pass
class OrderItem:
order: Order
is_recalled: bool
Customer has Orders
Order has OrderItems
Now we are trying to find all customers with at least one recalled order-item.(1)
This will not work properly
order_ids = OrderItem.objects \
.filter(is_recalled=True) \
.only("order_id")
customer_ids = OrderItem.objects \
.filter(id__in=order_ids) \
.only('customer_id')
# BROKEN! BROKEN
customers = Customer.objects.filter(id__in=customer_ids)
The code above looks very fine, but it produces the following query:
select * from customer where id in (
select id -- should be customer_id
from orders
where id in (
select id -- should be order_id
from order_items
where is_recalled = true))
Instead one should use select
order_ids = OrderItem.objects \
.filter(is_recalled=True) \
.select("order_id")
customer_ids = OrderItem.objects \
.filter(id__in=order_ids) \
.select('customer_id')
customers = Customer.objects.filter(id__in=customer_ids)
(1) Note: in a real case we might consider 'WHERE EXISTS'