Adding field to ManyToMany relationship Django ORM - django

So I'm building out a database where I need to have a field related to a specific ManyToMany relationship, but I don't know how to translate this into the Django ORM. For example, I have multiple Articles that can go with multiple Publications, but I want to see which article got the most views.
I figure that I could build the database like so:
+------------+--------+--------+-------+
| art_pub_id | art_id | pub_id | views |
+------------+--------+--------+-------+
| 101 | 201 | 301 | 6 |
+------------+--------+--------+-------+
| 102 | 201 | 302 | 4 |
+------------+--------+--------+-------+
| 103 | 202 | 301 | 8 |
+------------+--------+--------+-------+
Or I could do this
+------------+--------+--------+
| art_pub_id | art_id | pub_id |
+------------+--------+--------+
| 101 | 201 | 301 |
+------------+--------+--------+
| 102 | 201 | 302 |
+------------+--------+--------+
| 103 | 202 | 301 |
+------------+--------+--------+
+----+------------+-------+
| pk | art_pub_id | views |
+----+------------+-------+
| 1 | 101 | 6 |
+----+------------+-------+
| 2 | 102 | 4 |
+----+------------+-------+
| 3 | 103 | 8 |
+----+------------+-------+
I'm struggling with how to translate this to the Django ORM. I have the Article with the ManyToManyField pointing to the Publication, but I don't know where or how to place the views IntegerField. I have tried having a Publication_Article class that has two ManyToMany fields and my views field, but I'm not sure that is the right way to be doing it.
I also fully recognize that I may be approaching the problem wrong with my database design, in which case knowing the best way to do this would be invaluable for me.

Related

sqlite window function to get difference and product

I am using a window function to get the difference in the values of a column (downloads) between two dates. I'd also like to get the product of that difference multiplied by the size of the file to get the bytes downloaded for the period.
With the help of this community, I am able to get the number of downloads but cannot find the correct syntax to get the product of downloads * size.
Table 'files'
+---------------+------------------------+------+-----------+------------+
| site | full_path | size | downloads | date_stamp |
+---------------+------------------------+------+-----------+------------+
| Lawrenceville | lr1/dir1/subdir1/file1 | 1000 | 7 | 2019-08-08 |
| Lawrenceville | lr1/dir1/subdir1/file1 | 1010 | 9 | 2019-08-15 |
| Lawrenceville | lr1/dir1/subdir1/file2 | 1213 | 5 | 2019-08-08 |
| Lawrenceville | lr1/dir1/subdir1/file2 | 2000 | 5 | 2019-08-15 |
| Lawrenceville | lr1/dir2/subdir1/file1 | 2213 | 5 | 2019-08-15 |
| Rennes | rr1/dir1/subdir1/file3 | 200 | 3 | 2019-08-08 |
| Rennes | rr1/dir1/subdir1/file3 | 201 | 4 | 2019-08-15 |
+---------------+------------------------+------+-----------+------------+
SELECT site, sum(diff) FROM (SELECT site, downloads - lag(downloads, 1) OVER (PARTITION BY site, full_path ORDER BY date_stamp) AS diff FROM files WHERE date_stamp IN ('2019-08-15', '2019-08-08')) group by site
produces this:
+---------------+-----------+
| site | downloads |
+---------------+-----------+
| Lawrenceville | 2 |
| Rennes | 1 |
+---------------+-----------+
I have tried:
SELECT site, sum(diff), sum(sum(diff)*bytes) FROM (SELECT site, downloads - lag(downloads, 1), size OVER (PARTITION BY site, full_path ORDER BY date_stamp) AS diff, bytes FROM files WHERE date_stamp IN ('2019-08-15', '2019-08-08')) group by site
sqlite3.OperationalError: near "(": syntax error
Ideally I want this output:
+---------------+-----------+----------+
| site | downloads | bytes |
+---------------+-----------+----------+
| Lawrenceville | 2 | 2020 |
| Rennes | 1 | 201 |
+---------------+-----------+----------+
Lawrenceville had 2 downloads of file lr1/dir1/subdir1/file1 which is 1010 bytes (on 2019-08-15). File lr1/dir1/subdir1/file2 had no downloads for that period. It would be nice to include files lr1/dir1/subdir1/file2 and lr1/dir2/subdir1/file1 but they get excluded by the window function. I can get them with a separate query.
Rennes has 1 download of file rr1/dir1/subdir1/file3
If your current query works then you only need max() window function in the subquery:
SELECT site, sum(diff) downloads, sum(diff) * size bytes
FROM (
SELECT
site,
downloads - lag(downloads, 1) OVER (PARTITION BY site, full_path ORDER BY date_stamp) AS diff,
max(size) OVER (PARTITION BY site, full_path) AS size
FROM files
WHERE date_stamp IN ('2019-08-15', '2019-08-08')
)
group by site
See the demo.
Results:
| site | downloads | bytes |
| ------------- | --------- | ----- |
| Lawrenceville | 2 | 2020 |
| Rennes | 1 | 201 |

PowerBI: Use non-shown values for Drillthrough

I am trying to build a Power BI report for data from a SQL database where I have to show detail pages using Drillthrough. The only viable way to connect the datasets is using the database row ids.
From a user's perspective the row ids would not add any value but a lot of noise.
Is there a way to drillthrough using the row ids without showing them in a visual?
Yes, this is possible in the current release of Power Bi Desktop using a workaround solution that involves hiding the row id column in the parent (or summary) page.
Take the following tables as example:
ALBUM
+---------+------------------------+
| AlbumId | AlbumName |
+---------+------------------------+
| 1 | Hoist |
+---------+------------------------+
| 2 | The Story Of the Ghost |
+---------+------------------------+
TRACK
+---------+---------+--------------------------+
| TrackId | AlbumId | TrackName |
+---------+---------+--------------------------+
| 1 | 1 | Julius |
+---------+---------+--------------------------+
| 2 | 1 | Down With Disease |
+---------+---------+--------------------------+
| 3 | 1 | If I Could |
+---------+---------+--------------------------+
| 4 | 1 | Riker's Mailbox |
+---------+---------+--------------------------+
| 5 | 1 | Axilla, Part II |
+---------+---------+--------------------------+
| 6 | 1 | Lifeboy |
+---------+---------+--------------------------+
| 7 | 1 | Sample In a Jar |
+---------+---------+--------------------------+
| 8 | 1 | Wolfmans Brother |
+---------+---------+--------------------------+
| 9 | 1 | Scent of a Mule |
+---------+---------+--------------------------+
| 10 | 1 | Dog Faced Boy |
+---------+---------+--------------------------+
| 11 | 1 | Demand |
+---------+---------+--------------------------+
| 12 | 2 | Ghost |
+---------+---------+--------------------------+
| 13 | 2 | Birds of a Feather |
+---------+---------+--------------------------+
| 14 | 2 | Meat |
+---------+---------+--------------------------+
| 15 | 2 | Guyute |
+---------+---------+--------------------------+
| 16 | 2 | Fikus |
+---------+---------+--------------------------+
| 17 | 2 | Shafty |
+---------+---------+--------------------------+
| 18 | 2 | Limb by Limb |
+---------+---------+--------------------------+
| 19 | 2 | Frankie Says |
+---------+---------+--------------------------+
| 20 | 2 | Brian and Robert |
+---------+---------+--------------------------+
| 21 | 2 | Water in the Sky |
+---------+---------+--------------------------+
| 22 | 2 | Roggae |
+---------+---------+--------------------------+
| 23 | 2 | Wading in the Velvet Sea |
+---------+---------+--------------------------+
| 24 | 2 | The Moma Dance |
+---------+---------+--------------------------+
| 25 | 2 | End of Session |
+---------+---------+--------------------------+
Add them as data sources. The 1:many relationship between AlbumId should be created. Create a parent page with a table containing AlbumId and AlbumName. Then create the details page with a table containing only the TrackName column. In the Drillthrough filter field of the details page, drag the Album Table -> AlbumId to this field.
Now go back to the parent page and notice that when you right click on an album, you get the drillthrough menu to the details page. This works, but now you have a messy AlbumId column on your parent page.
The workaround is to hide the AlbumId on the parent report. First go to the Format(Paint roller) menu of the table on the parent report and in the column header -> word wrap turn this off. Then drag the column separator of the table to hide the AlbumId. See before and after images below.
BEFORE HIDE
AFTER HIDE
I have the powerbi file posted here if you want to see it in action.

unique column value per row

I find it best to use an example, so here we go:
Say I have a table with chores and a table with a weekly schedule like this:
CHORES:
|----+---------------+----------+-------|
| id | name | type | hours |
|----+---------------+----------+-------|
| 1 | clean kitchen | cleaning | 4 |
|----+---------------+----------+-------|
| 2 | clean toilet | cleaning | 3 |
etc
SCHEDULE:
|------+---------------+---------------+-----|
| week | monday | tuesday | etc |
|------+---------------+---------------+-----|
| 1 | clean kitchen | clean toilet | etc |
|------+---------------+---------------+-----|
| 2 | clean toilet | clean kitchen | etc |
etc
I want to make sure that for one week, you can't have duplicate cells, so this wouldn't be allowed:
SCHEDULE:
|------+---------------+--------------+-----|
| week | monday | tuesday | etc |
|------+---------------+--------------+-----|
| 1 | clean toilet | clean toilet | etc |
etc
What would I have to do in my models.py to get this behaviour?
Try django unique-together in model meta option.
https://docs.djangoproject.com/en/1.11/ref/models/options/#unique-together
I'd better user ManyToMany through another table like that:
SCHEDULE:
------+------------------------+
| week | chores |
|------+------------------------+
| 1 | many to many to chores |
|------+------------------------+
| 2 | many to many to chores |
And trough table like that
THROUGH TABLE:
|---------+---------------+---------------+
| week_id | day of week | chores_id |
|---------+---------------+---------------+
| 1 | Monday | clean toilet |
|---------+---------------+---------------+
| 1 | Tuesday | clean kitchen |
And in that table make unique together for week_id and chores_id

Django model get unique foreign key rows based on other column max value

I'm new to Django, and I'm trying to create a simple application that keep track on different server configurations in a SQlite database. I've created 2 database models:
from django.db import models
class Server(models.Model):
name = models.CharField(max_length=250)
class Config(models.Model):
server = models.ForeignKey(Server, on_delete=models.CASCADE)
configuration = models.CharField(max_length=250)
config_version = models.IntegerField()
Here are the 2 models sample data:
Server:
| id | name |
| ------ | ------ |
| 1 | Server1 |
| 2 | Server2 |
| 3 | Server3 |
Config:
| id | configuration | config_version | server |
| ------ | ------------- | -------------- | ------ |
| 1 | srv1_cfg1 | 1 | 1 |
| 2 | srv2_cfg1 | 1 | 2 |
| 3 | srv2_cfg2 | 2 | 2 |
| 4 | srv2_cfg3 | 3 | 2 |
| 5 | srv3_cfg1 | 1 | 3 |
| 6 | srv1_cfg2 | 2 | 1 |
| 7 | srv1_cfg3 | 3 | 1 |
I would like to query the Config table, and get only rows with the maximum value of "config_version" field for each server id, like:
Desired result:
| id | configuration | config_version | serverid | servername |
| ------ | ------------- | -------------- | -------- | ---------- |
| 4 | srv2_cfg3 | 3 | 2 | Server2 |
| 5 | srv3_cfg1 | 1 | 3 | Server3 |
| 7 | srv1_cfg3 | 3 | 1 | Server1 |
I've tried many different options to construct the correct query, but so far I cannot get what I want. My best result is to query the Server table:
Server.objects.annotate(maxver=Max('config__config_version'))
But it seems I cannot get access to the Config table objects, so I guess I need to query the Config table with some filtering?
I can do this with a raw SQL query, but I would strongly prefer to do it the "Django" way. Any help will be much appreciated.
After some more struggle with this, I've came with a solution that works for me. I'm sure it is not optimal, but at least seems to works:
from django.db.models import Max, F
s1 = Config.objects.annotate(maxver=Max('server__config__config_version'))
config_list = s1.filter(config_version=F('maxver'))
If there is a better way to do this, I would love to know it.

Two outer joins in django's queryset (for language fall back case)

I have two models, Version and Description.
class Version(models.Model):
version_name = models.CharField(max_length=100)
version_value = models.IntegerField()
url = models.CharField(max_length=240)
class Description(models.Model):
version = models.ForeignKey(Version)
lang = models.CharField(max_length=8)
content = models.TextField()
And a DescriptionSerializer.
class DescriptionSerializer(serializers.ModelSerializer):
version_name = serializers.RelatedField(source='version')
class Meta:
model = Description
fields = ('version_name', 'content')
They stored the descriptions of different versions in different languages.
E.g.
Version
+----+--------------+---------------+---------------------+
| id | version_name | version_value | url |
+----+--------------+---------------+---------------------+
| 1 | 1.0.0 | 1 | http://abc.net.tw/ |
| 2 | 1.0.1 | 2 | http://abc.net.tw/2 |
| 3 | 1.0.2 | 3 | http://abc.net.tw/3 |
| 4 | 1.0.3 | 4 | http://abc.net.tw/4 |
| 7 | 1.1.0 | 5 | http://abc.net.tw/5 |
| 8 | 1.1.1 | 6 | http://abc.net.tw/6 |
+----+--------------+---------------+---------------------+
Description
+------------+-------+---------+
| version_id | lang | content |
+------------+-------+---------+
| 1 | en_US | English |
| 1 | zh_TW | Chinese |
| 1 | es_ES | Spanish |
| 2 | en_US | English |
| 2 | zh_TW | Chinese |
| 2 | es_ES | Spanish |
| 3 | en_US | English |
| 3 | zh_TW | Chinese |
| 3 | es_ES | Spanish |
| 4 | en_US | English |
| 7 | en_US | English |
| 8 | en_US | English |
| 4 | es_ES | Spanish |
| 7 | es_ES | Spanish |
+------------+-------+---------+
I'm using django rest framework to implement a web API that returns the description of each version in certain language. If a description of certain language doesn't exist, use English version instead.
I can use following SQL to retrieve the desired result. I've read DRF's docs on relatedField and reverse relation. But I still can't figure out how to use django's ORM to do the same thing and to use it with django rest framework's serializer.
select
coalesce(d.id, d2.id), coalesce(d.version_id, d2.version_id), coalesce(d.lang, d2.lang), coalesce(d.content, d2.content)
from
version v
left outer join description d on v.id = d.version_id and d.lang='zh_TW'
left outer join description d2 on v.id = d2.version_id and d2.lang='en_US'
Please advise how to do it in django.
You can't use django orm for everything. There are numerous things you can't do with django. For those cases you either use straight up SQL (from django.db import connection, transaction etc...) or if the query results can be worked into objects you have described - then you can use raw queries (link)