Django queryset EXCLUDE: are these equivalent? - django

In Django, are these two equivalent?
Cars.objects.exclude(brand='mercedes').exclude(year__lte=2000)
and
Cars.objects.exclude(brand='mercedes', year__lte=2000)
?
I know the first one says: exclude any mercedes and exclude any car older than year 2000.
What about the second one? Does it say the same? Or it does only exclude the combination of mercedes being older than year 2000?
Thanks!

The two are not equivalent.
As is specified in the documentation on exclude(..):
The lookup parameters (**kwargs) should be in the format described in Field lookups below. Multiple parameters are joined via AND in the underlying SQL statement, and the whole thing is enclosed in a NOT().
So the first query can be read as:
-- first query
SELECT car.*
FROM car
WHERE NOT (brand = 'mercedes') AND NOT (YEAR <= 2000)
whereas the latter is equivalent to:
-- second query
SELECT car.*
FROM car
WHERE NOT (brand = 'mercedes' AND YEAR <= 2000)
The first query this is semantically the same as "All cars that are not a Mercedes; and that are not build before or in the year 2000". Whereas the second query is "All cars except Mercedeses that are built before or in the year 2000.".
So in case the table contains a Ford that is built in 1993, then the first query will not include it, whereas the second will, since the brand is not Mercedes, it is not excluded (so it will be part of the queryset).

Related

How to print the objects created last month instead of using datetime.timedelta(days=30)

I am making a Django app to print the expenses made each month
I have been searching since a long time how to print the objects(expenses) created in a specific month(or may be last month)
I checked across many stack overflow questions similar to this but was not able to find an appropriate answer.
Many people use
datetime.timedelta(days=30)
But how can this method be proper to print the expenses of a particular month.
I want to use a method like
datetime.timedelta(previous month)
Is there any possible way to do this?
Here is a good way to do that
First of all, in your views.py file :
Start with declaring today's date
today = datetime.date.today()
You need to filter out the objects created last month (taking May month as an example here)
may_month_expenses =
Expenses.objects.filter(created__month='05',created__year=today.year)
Explanation:
Expenses is the name of the model
objects.filter() is used to print the objects which satisfy the
conditions in the brackets.
created is a DateTimeField in Expenses
created__month='05' specifies that the object should have been created
in May(month number 5)
created__year = today.year is important as you want to print the objects
created in month May of this year(2021) only.
This prints the objects created in month May of year 2021

Power BI DAX Functions not Working Because of Star Schema Relationships

I've been trying to create my first star schema based on Google Classroom data for a week. I put a description of the tables from my most recent attempt below. I didn't list descriptive fields not relevant to my question.
I have a table visual that shows CourseName, StudentsEnrolled (it works)
StudentsEnrolled = CALCULATE(DISTINCTCOUNT(gc_FactSubmissions[StudentID]))
I am trying to create a table visual that shows StudentName, CourseWorkTitle, PointsEarned, MarkPct.
MarkPct =
divide(sum(gc_FactSubmissions[PointsEarned]),sum(gc_DimCourseWork[MaxPoints]))
When I try to add StudentName to the visual, I end up with incorrect results (some blank student names and incorrect totals). When I try to use DAX Related(), I can only select fields in the Submissions table.
I’ve spent countless hours of Googling sites/pages like the following one and others:
https://exceleratorbi.com.au/the-optimal-shape-for-power-pivot-data/
I think the problem is the gc_DimStudents table because it contains a student record for every student that is enrolled in a gc_DimCourses. Not all students enrolled have submitted assignments, so if I limited the gc_DimStudents to only the StudentIDs in gc_FactSubmissions, then I won’t be able to get a count of StudentsEnrolled in courses.
I’m not sure how to resolve this. Should gc_DimCourses also be made into a fact table? With a gc_DimCourseStudents and a gc_DimSubmissionStudents? Then I’d have to create a surrogate key to join gc_FactSubmissions to the new gc_FactCourses? If that is true, then as I add more fact tables to my model, is it normal to have many DimAnotherStudentList in many places in a Star Schema model?
I want to keep building on this star schema because we want reports/dashboards that relate things like online marks, to attendance, to disciplinary actions, etc., etc. So I want to get the relationships correct this time.
Any help is very much appreciated.
Thanks,
JMC
gc_FactSubmissions (contains one record for every combination of the 4 ID fields, no blanks)
CourseID (many to 1 join to gc_Dimcourses.CourseID )
OwnerID (many to 1 join to gc_DimOwners.OwnerID)
CourseWorkID (many to 1 join to gc_DimCourseWork.CourseWorkID)
StudentID (many to 1 join to gc_DimStudents)
SubmissionID
SubmissionName
PointsEarned (int, default to sum)
(other descriptive fields)
gc_DimCourseWork (one CourseWorkID for each gc_FactSubmissions.CourseWorkID)
CourseWorkID (it is distinct, no blanks)
CourseWorkName
MaxPoints (int, default to sum)
(other descriptive fields)
gc_DimCourses (one CourseID for each gc_FactSubmissions.Course CourseID)
CourseID (it is distinct, no blanks)
CourseName
(other descriptive fields)
gc_DimOwners (one OwnerID for each gc_DimOwners.OwnerID)
OwnerID (it is distinct, no blanks)
OwnerName
(other descriptive fields)
gc_DimStudents (one StudentID for each gc_FactSubmissions.Course CourseID)
StudentID (distinct, no blanks)
StudentName
(other descriptive fields)
A Snowflake Schema is one where Dimensions are related to each other directly rather than via a Fact table - so no, adding another fact table to your model doesn't make it a Snowflake.
An Enrolment fact would have FKs to any Dimensions that are relevant to Enrolments - so Course, Student, probably at least 1 date and whatever other enrolment attributes there may be.
As an additional comment, while there are many incorrect ways of modelling a star schema there can also be many correct ways of modelling it: there is rarely one correct answer. For example, for your Submissions Star you could denormalise your Course data into your CourseWork Dim and possibly also include the Owner data (I assume Owner is Owner of the course?). The fewer joins there are in any query the better the performance. If another fact, such as Enrolment, needed to be related to a Course Dim (rather than to Coursework) then you'd need to consider the trade-off in performance of having fewer joins to one fact and having to maintain the course data in two different Dims (Course and Coursework).
As a star schema is denormalised there is no issue with the same data appearing in multiple tables (within reason). The most common example is a Date Dim that has date, week, month and year attributes and a Month Dim that has just month and year attributes.

filter statement based on calculations django orm

how can I translate query like this in django orm?
select id, year, month
where (year*100 + month) between 201703 and 201801
Thanks in advance for any help
You can first create an annotation, and then filter on that:
from django.db.models import F
(Modelname.objects
.annotate(yearmonth=F('year')*100+F('month'))
.filter(yearmonth__range=(201703, 201801)))
So here we construct an annotation yearmonth (you can use another name if you like), and make it equal to the year column times 100 plus the month column. Next we can filter on that annotation, and do so by specifying a __range here with two bounds.
Normally this will work for any database system that performs the operations you here perform (multiplying a column with a constant number, adding two values together), as well as do the __range filter (in MySQL this is translated into <var> BETWEEN <min> AND <max>). Since we use Django ORM however, if we later decide to use another database, the query will be translated in the other database query language (given of course that is possible).
How about using something similar to this.
Did you try filter and __range
Created_at will be the field in your DB
ModelName.objects.filter(created_at__range=(start_date, end_date))
Later you can do calculation in your view this is just a workaround.
If you want to run the exactly same query then probably you can run using.
ModelName.objects.raw("select id, year, month
where (year*100 + month) between 201703 and 201801")

What are good approaches to Django yearless date ranges

I need to store start and ending dates to save holidays.
I don't care about the year part of dates, as a holiday will repeat every year.
Also I need to be able to query this dates to see if a random datetime is in the range. And even when I don't want years stored, the query must understand that a holiday can start in one year and end next year (i.e. Dec 25th to Jan 4th).
Previously I was storing the dates as DateTimeFields, then iterating over each stored holiday and checking if a given target date was inside the dates range. This was made in Python and forced me to evaluate the QuerySets into lists and finally add the value using something like getattr(result, 'is_a_holiday', value)
As performance issues have arise I want to move this into an annotation (so I can keep the queryset with select_related and prefetch_related data) and make the database (Postgresql) do the query part, but then I run into the problem that the database considers the year, and thus a date inside a holiday for this year is not considered inside a holiday the previous year or next year.
I've already tried django-yearlessdate and annotating with conditional expressions and F expressions (to check when a year changes) but it is not working as expected: when there are several holidays some of the condition cases don't match and I just get the default return value.
What are other/different approaches to this problem?
If you don't need year, you can create two separate fields in your model to hold month and day separately:
class Holiday(...):
month = models.PositiveSmallIntegerField()
day = models.PositiveSmallIntegerField()
Then to find holidays between a given range, you can do this:
from_date = <datetime object>
to_date = <datetime object>
Holiday.objects.filter(month__range[from_date.month, to_date.month],
day__range[from_date.day, to_date.day]
)

Search a column for multiple words using Django queryset

I have an autocomplete box which needs to return results having input words. However the input words can be partial and located in different order or places.
Example:
The values in database column (MySQL)-
Expected quarterly sales
Sales preceding quarter
Profit preceding quarter
Sales 12 months
Now if user types quarter sales then it should return both of the first two results.
I tried:
column__icontains = term #searches only '%quarter sales% and thus gives no results
column__search = term #searches any of complete words and also returns last result
**{'ratio_name__icontains':each_term for each_term in term.split()} #this searches only sales as it is the last keyword argument
Any trick via regex or may be something I am missing inbuilt in Django since this is a common pattern?
Search engines are better for this task, but you can still do it with basic code.
If you're looking for strings containing "A" and "B", you can
Model.objects.filter(string__contains='A').filter(string__contains='B')
or
Model.objects.filter(Q(string__contains='A') & Q(string__contains='B'))
But really, you'd be better going with a simple full text search engine with little configuration, like Haystack/Whoosh
The above answers using chained .filter() require entries to match ALL the filters.
For those wanting "inclusive or" or ANY type behaviour, you can use functools.reduce to chain together django's Q operator for a list of search terms:
from functools import reduce
from django.db.models import Q
list_of_search_terms = ["quarter", "sales"]
query = reduce(
lambda a, b: a | b,
(Q(column__icontains=term) for term in list_of_search_terms),
)
YourModel.objects.filter(query)