Django: ManyToManyField with additional Column - sql

I am trying to create a job application-form with Django.
Basically, I created two models.
softwareskill_model
application_model
The admin can log into the admin-section and add new softwareskill-
entries to the database. The application_model references those
softwareskill-entries/records using a ManyToMany-Field:
class softwareskill_model(django.db.models.Model):
name = django.db.models.CharField(max_length=200)
class application_model(django.db.models.Model):
# ...
softwareskills = django.db.models.ManyToManyField(softwareskill_model)
So if someone wants to apply for the job, he can select which
software-packages he uses.
Now I want the applicant to make a rating from 1-6 for each software-skill
he has selected. How do you do that?
I am using a SQLite3 database and discovered that the ManyToManyField
creates a new table to store the relationship. In my case it looks like
this:
| ID | application_model_id | softwareskill_model_id |
My assumption would be to simply add a new column so it looks like this:
| ID | application_model_id | softwareskill_model_id | Rating |
Is that possible / the best way to do it? How?
I am very new to Django, databases and web-development in general and hope
you can help me :-)!
Thank you,
Henry

through is what you need to use, e.g.
class softwareskill_model(django.db.models.Model):
name = django.db.models.CharField(max_length=200)
class application_model(django.db.models.Model):
# ...
softwareskills = django.db.models.ManyToManyField(softwareskill_model, through="ApplicationSoftwareSkill")
class ApplicationSoftwareSkill(models.Model):
softwareskill = models.ForeignKey(softwareskill_model)
application = models.ForeignKey(application_model)
# extra fields here e.g.
rating = models.IntegerField()

Related

How to make this very complicated query from three connected models with Django ORM?

Good day, everyone. Hope you're doing well. I'm a Django newbie, trying to learn the basics of RESTful development while helping in a small app project. We currently want some of our models to update accordingly based on the data we submit to them, by using the Django ORM and the fields that some of them share wih OneToMany relationsips. Currently, there's a really difficult query that I must do for one of my fields to update automatically given that filter. First, let me explain the models. This are not real, but a doppleganger that should work the same:
First we have a Report model that is a teacher's report of a student:
class Report(models.Model):
status = models.CharField(max_length=32, choices=Statuses.choices, default=Statuses.created,)
student = models.ForeignKey(Student, on_delete=models.CASCADE,)
headroom_teacher = models.ForeignKey(TeacherStaff, on_delete=models.CASCADE,)
# Various dates
results_date = models.DateTimeField(null=True, blank=True)
report_created = models.DateTimeField(null=True, blank=True)
.
#Other fields that don't matter
Here we have two related models, which are student and headroom_teacher. It's not necessary to show their models, but their relationship with the next two models is really important. We also have an Exams model:
class Exams(models.Model):
student = models.ForeignKey(student, on_delete=models.CASCADE,)
headroom_teacher = models.ForeignKey(TeacherStaff, on_delete=models.CASCADE,)
# Various dates
results_date = models.DateTimeField(null=True, blank=True)
initial_exam_date = models.DateTimeField(null=True, blank=True)
.
#Other fields that don't matter
As you can see, the purpose of this app is akin to reporting on the performance of students after completing some exams, and every Report is made by a teacher for specific student on how he did on those exams. Finally we have a final model called StudentMood that aims to show how should an student be feeling depending on the status of their exams:
class StudentMood(models.Model):
report = models.ForeignKey(Report, on_delete=models.CASCADE,)
student_status = models.CharField(
max_length=32, choices=Status.choices,
default=None, null=True, blank=False)
headroom_teacher = models.ForeignKey(TeacherStaff, on_delete=models.CASCADE,)
And with these three models is that we arrive to the crux of the issue. One of our possible student_status options is called Anxious for results, which we believe a student will feel during the time when he already has done an exam and is waiting for the results.
I want to automatically set my student_status to that, using a custom manager that takes into account the date that the report has been done or the day the data has been entered. I believe this can be done by making a query taking into account initial_exam_date.
I already have my custom manager set up, and the only thing missing is this query. I have no choice but to do it with Django's ORM. However, I've come up with an approximate raw SQL query, that I'm not sure if it's ok:
SELECT student_mood.id AS student_mood_id FROM
school_student_mood LEFT JOIN
school_reports report
ON student_mood.report_id = report.id AND student_mood.headroom_teacher_id = report.headroom_teacher_id
JOIN school_exams exams
ON report.headroom_teacher_id = exams.headroom_teacher_id
AND report.student_id = exams.student_id
AND exams.results_date > date where the student_mood or report data is entered, I guess
And that's what I've come to ask for help. Could someone shed some light into how to transfer this into a single query?
Without having an environment setup or really knowing exactly what you want out of the data. This is a good start.
Generally speaking, the Django ORM is not great for these types of queries, and trying to use select_related or prefetches results in really complex and inefficient queries.
I've found the best way to achieve these types of queries in Django is to break each piece of your puzzle down into a query that returns a "list" of ids that you can then use in a subquery.
Then you keep working down until you have your final output
from django.db.models import Subquery
# Grab the students of any exams where the result_date is greater than a specific date.
student_exam_subquery = Exam.objects.filter(
results_date__gt=timezone.now()
).values_list('student__id', flat=True)
# Grab all the student moods related to reports that relate to our "exams" where the student is anxious
student_mood_subquery = StudentMood.objects.filter(
student_status='anxious',
reports__student__in=Subquery(student_exam_subquery)
).values_list('report__id', flat=True)
# Get the final list of students
Student.objects.values_list('id', flat=True).filter(
reports__id__in=Subquery(student_mood_subquery)
)
Now I doubt this will work out of the box, but it's really to give you an understanding of how you might go about solving this in a way that is readable to future devs and the most efficient (db wise).
So, the issue I was running into, is that the school has exam cycles each period, and it was difficult to retrieve only the students' report for this cycle. Let's assume we have the following database:
+-----------+-----------+----------------+-------------------+-------------------+------------------+
| Student | Report ID | StudentMood ID | Exam Cycle Status | Initial Exam Date | Report created a |
+-----------+-----------+----------------+-------------------+-------------------+------------------+
| Student 1 | 1 | 1 | Done | 01/01/2020 | 02/01/2020 |
| Student 2 | 2 | 2 | Done | 01/01/2020 | 02/01/2020 |
| Student 1 | 3 | 3 | On Going | 02/06/2020 | 01/01/2020 |
| Student 2 | 4 | 4 | On Going | 02/06/2020 | 01/01/2020 |
+-----------+-----------+----------------+-------------------+-------------------+------------------+
And Obviously, I wanted to limit my query to just this cycle, like this:
+-----------+-----------+----------------+-------------------+-------------------+------------------+
| Student | Report ID | StudentMood ID | Exam Cycle Status | Initial Exam Date | Report created a |
+-----------+-----------+----------------+-------------------+-------------------+------------------+
| Student 1 | 3 | 3 | On Going | 02/06/2020 | 01/01/2020 |
| Student 2 | 4 | 4 | On Going | 02/06/2020 | 01/01/2020 |
+-----------+-----------+----------------+-------------------+-------------------+------------------+
Now, your answer, trent, was really useful, but I'm still having issues retrieving in the shape of the above:
qs_exams = Exams.objects.filter(initial_exam_date__gt=now()).values_list('student__id', flat=True)
qs_report = Report.objects.filter(student__id__in=qs_exams).values_list('id', flat=True)
qs_mood = StudentMood.objects.select_related('report') \
.filter(report__id__in=qs_report).order_by('report__student_id', '-created').distinct()
But this query is still giving me all the StudentMoods throughout the school year. Sooooo, any ideas?

How to make power bi work with many to many?

I have the following model, where the relation tables create a many to many relationship, as usual.
|Table car | |relation car worker|
|Id car |1----*|id car |
|car things| |id worker |*-----
|
|
|table worker | /
|id worker |1----------/
|worker things | \
\_______________
\
|table building | |relation worker building| |
|id building |1----*|id building | |
|building things| |id worker |*---------
When I load this model in Power Bi, it can build a table visualization (and others) containing one of the following:
Option 1:
Car things
Worker things
Option 2:
Worker things
Building things
But it totally fails when I try to put in the table visualization something from the edges of the model:
Car things
Building things
This is the error:
What's going on here? Why the error?
Basically I need to see which cars visit which buildings (and do one or two summarizations)
From what i can understand from your model.. you need to set your cross filter direction to both rather than single so it can filter back up the tables
Here is an example which may help you to understand
For example, for 1 from tableA, it can relate 1 or 2 from tableB, since 1 from Table B can also relate 1 or 2 from tableC, so for 1 from tableA, it can’t determine whether 1 or 2 from tableC should be refer to
*----------------------------*
|Table A Table B Table C |
*----------------------------*
| 1 1 1,2 |
| 1 2 1,2 |
*----------------------------*
You can create a new table with the formula
tableName = CROSSJOIN(tableA,tableB,tableC....tableZ)
I had to create a new table as if I were doing an inner join in SQL (which works just as expected).
Click "modeling", "create table".
For the formula:
NewTable = NATURALINNERJOIN(tb_cars,
NATURALINNERJOIN(tb_rel_car_worker,
NATURALINNERJOIN(tb_workers,
NATURALINNERJOIN(tb_rel_worker_building, tb_buildings))))
Then I start using everything from this table instead of the others.
In order to create metrics that include zero counts grouped by one of the edge tables, I had to leave this table separate:
Partial Table= NATURALINNERJOIN(tb_rel_car_worker,
NATURALINNERJOIN(tb_workers,
NATURALINNERJOIN(tb_rel_worker_building, tb_buildings))))
Then in the relationship editor, I added a relation between Partial Table[id_car] and tb_cars[id_car].
Now the metrics grouped by car can use the technique of adding +0 to the DAX formulas to show also cars whose metric sum zero in charts.

How to create value Buffer in Pentaho Kettle Transformation

I have some values coming in over time(stream) and over some different rows, which need to be processed as one row.
The incoming data looks kind of like this:
|timestamp |temp|otherStuff|
|------------|----|----------|
|... | |other |
|04:20:00.321|19.0|other |
|04:20:01.123|20.5|other |
|04:20:02.321|22.5|other |
|04:20:03.234|25.5|other |
|04:20:04.345|23.5|other |
|...(new data coming in) |
What I need could look something like this:
|val0|val1|val2|...|valN |
|----|----|----| |------|
|... create new row, |
|as new data arrives |
|23.5|25.5|23.5|...|valN |
|25.5|22.5|20.5|...|valN-1|
|22.5|20.5|19.0|...|valN-2|
I didn't find a good way to solve this with kettle. I'm also using a data service, (Basically a database, with a predefined amount of rows which refresh, as soon as a new dataset arrives) that holds the data in the same way as displayed in the first example.
That means I also could use SQL to flip the table around (which I don't know how to do either). It wouldn’t be as clean as using kettle but it would do the trick.
For better understanding, another example: This is what is coming in:
And something like this is what I need my data to transform to:
Is there any good way of achiving this?
Cheers.
Thank you #jxc,
the Analytic Query step did the trick.
Here's a screenshot of how I did it.
as #jxc stated, you have to
Add N+1 fields with Subject = temp, Type = Lag N rows BACKWARD in get Subject and N from 0 to N
(temp = Value in my case)

When using vb.net I need to join 2 datatables to just 1 gridview

I have been searching through a lot of different forums, but havent found the help I am looking for, so here we go.
First of all I should inform you that I am well aware, that 1 solution could be to do a SQL join in my sql statement, however this is not so easy as I am using 2 different tables from 2 different databases. So I am interesting in hearing in another solution.
As it is now, I have made 2 queries, and made 2 datatables, and 2 gridviews.
I have succeeded in binding the data in the 2 gridviews, and now I kinda want to "merge" them based on 1 column that they share.
How to do this in VB.net I don't know.
Basically I have 1 table in the database dbo_db_Test_Palle on the server OKPalle. From this I take the following columns and put into my datatable dt and bind to gridview 1.
| Name | ID | Organisation |
In another datatable (dt2) from dbo_db_Test_Palle2 from the server NOTokPalle I take the following columns and put into dt2, and bind to Gridview 2.
| Nickname | City | Hobby | ID
What I would like to show in just one GridView is:
| Name | ID | Organisation | Nickname | City | Hobby |
So basically I wish to add City and Hobby columns, from dt2 to dt, where the posts with ID matches (others I just leave blank).
I really hope someone out here can help me.
Something like this, but it's been a while since I've done this, you might need to hack around with it a little.
Dim ds As New DataSet
ds.Tables.Add(dt)
ds.Tables.Add(dt2)
ds.Relations.Add("rel", dt2.Columns("ID"), dt.Columns("ID"), False)
dt.Columns.Add("Nickname", GetType(System.String), "Parent.Nickname")
dt.Columns.Add("City", GetType(System.String), "Parent.City")
dt.Columns.Add("Hobby", GetType(System.String), "Parent.Hobby")

SQL / (Django) : efficient database schema for translations

Situation
I trying to set up a database schema to store translations, between different languages. So far it looks like this (simplyfied):
class Language(models.Model):
tag = models.CharField(max_length=2)
def __unicode__(self):
return self.tag
class Phrase(models.Model):
name = models.TextField()
language = models.ForeignKey(Language)
def __unicode__(self):
return self.name
class Meta:
unique_together = ("name", "language")
index_together = [
["name", "language"]
]
class Translation(models.Model):
phrase1 = models.ForeignKey(Phrase, related_name="translation_as_1")
phrase2 = models.ForeignKey(Phrase, related_name="translation_as_2")
def __unicode__(self):
return self.phrase1.name + " <=> " + self.phrase2.name
class Meta:
unique_together = ("phrase1", "phrase2")
index_together = [
["phrase1", "phrase2"]
]
This database schema seems logical to me. I store phrases in different languages and then have translations that contain exactly two phrases.
Problem
The problem is, that the queries, that result out of this schema, look kind of nasty. For instance:
from django.db.models import Q
name = "my phrase"
translations = Translation.objects.filter(Q(phrase1__name=text)|Q(phrase2__name=text))
translated_names = []
for translation in translations:
name1 = translation.phrase1.name
name2 = translation.phrase2.name
if name1 == name:
translated_names.append(name2)
else:
translated_names.append(name1)
I always have to include the "OR" relationship, to make sure, that I get all the possible translations, since the phrase could be stored as phrase1 or phrase2. On top of that, I have to filter my result afterwards to get the correct translated_name (for loop).
Further Explaination
Before I switched to the described schema, I had the following schema instead (Phrase and Language are the same as before):
class Translation(models.Model):
phrase = models.ForeignKey(Phrase)
name = models.TextField()
def __unicode__(self):
return self.phrase.name + " => " + self.name
class Meta:
unique_together = ("phrase", "name")
index_together = [
["phrase", "name"]
This schema let me make queries like this:
from django.db.models import Q
name = "my phrase"
translations = Translation.objects.filter(phrase__name=text)
translated_names = [t.name for t in translations]
This looks much nicer, and is of course faster. But this schema had the disadvantage, that it presents translations only in one direction, so I moved to the other one, which isn't quite what I want as well, because too slow and too complicated queries.
Question
So is there a good schema for this kind of problem, that I maybe overlook?
Remark
I'm not only interested in Django related answers. A pure SQL schema for this kind of problem would also be interesting for me.
This is the way that I have done it in the past. Adapt it for your naming convention.
Suppose that I had a table with a name and other columns in it like this
Table TR_CLT_clothing_type
clt_id | clt_name | other columns ....
--------------------------------------
1 | T Shirt ...
2 | Pants ...
Now if I decided that it needs translations, first I make a languages table
Table TR_LNG_language
lng_id | lng_name | lng_display
-------------------------------
1 | English | English (NZ)
2 | German | Deutsch
I also need to store the current language in the database (you will see why soon). It will only have one row
Table TA_INF_info
inf_current_lng
---------------
1
Then I drop the clt_name column from my clothing table TR_CLT_clothing_type. Instead I make relation table.
Table TL_CLT_clothing_type
clt_id | lng_id | clt_name
--------------------------
1 | 1 | T Shirt
1 | 2 | (German for T-Shirt)
2 | 1 | Pants
2 | 2 | keuchen (thank you google translate)
Now to get the name, you want to make a stored procedure for it. I have not attempted this in ORM.
CREATE PROCEDURE PS_CLT
#clt_id int
AS
SELECT lng.clt_name, clt.*
FROM TR_CLT_clothing_type clt
JOIN TL_CLT_clothing_type lng
ON lng.clt_id = clt.clt_id
WHERE clt.clt_id = #clt_id AND
lng.lng_id in (SELECT inf_current_lng FROM TA_INF_info)
This stored proc will return the name in the current language and all other columns for a specified language. To set the language, set the clt_current_lng in the TA_INF_info table.
Disclaimer: I don't have anything to check the syntax of what I have typed but it should hopefully be straightforward.
-- EDIT
There was a concern to be able to do "give me all translations for word X in language Y to language Z"
There is a "not so elegant" way to do this with the schema. You can do something like
for each table in database like "TL_%"
SELECT name
FROM table
WHERE id IN ( SELECT id
FROM table
WHERE name = #name
AND lng_id = german
)
AND lng_id = english
Now I would imagine that this would require some auto-generated SQL code but I could pull it off.
I have no idea how you would do this in ORM