I'm working on a user/group API (using django-rest-framework for most things), and am getting hung up on the settings dict that is part of each object.
My basic models look like this:
class Group(models.Model):
name = models.CharField(null=False, unique=True)
is_active = models.BooleanField(null=False, default=True)
description = models.CharField(max_length=512)
class User(models.Model):
name = models.CharField(null=False, unique=True, db_index=True)
group = models.ForeignKey('Group', related_name='users')
is_active = models.BooleanField(null=False, default=True)
The JSON returned is simple (views omitted, only notable thing is that I'm not using a PrimaryKeyRelatedField for the users field).
Group:
{
"id": 1,
"name": "Basic Group",
"is_active": true,
"description": "Just a simple group",
"users": [
"Test User 1",
"Test User 2"
]
}
Users:
{
"id": 1,
"name": "Test User 1",
"group": 1,
"is_active": true
}, {
"id": 2,
"name": "Test User 2",
"group": 1,
"is_active": true
}
I would like to enhance this by having a "settings" dict for both Group and User object types, that are overriding. That is, the settings dict for a Group will include all global settings, unless a setting with the same name has been set on the group. Similarly, the settings dict for a user will have all of the global settings, overridden by group settings, unless a setting with the same name has been set for the user.
Imagine a structure approximately like the following:
name | value | group | user
--- | --- | --- | ---
setting 1 | value 1 | |
setting 1 | value 2 | 1 |
setting 2 | SKFJDL | 1 |
setting 2 | ABCD | 1 | 2
This would result in the following JSON being returned for Group 1:
{
"id": 1,
"name": "Basic Group",
"is_active": true,
"description": "Just a simple group",
"users": [
"Test User 1",
"Test User 2"
],
"settings": {
"setting 1": "value 2",
"setting 2": "SKFJDL"
}
}
For User 1, the settings dict would look like:
"settings": {
"setting 1": "value 2",
"setting 2": "SKFJDL"
}
For User 2, it looks like:
"settings": {
"setting 1": "value 2",
"setting 2": "ABCD"
}
This leaves me with two issues.
Issue 1: The SQL that gets me the desired output is relatively complex. Basically:
SELECT DISTINCT(name) *
FROM (
(SELECT * FROM setting WHERE group IS NULL AND user IS NULL)
UNION ALL
(SELECT * FROM setting WHERE group = 1 AND user IS NULL)
UNION ALL
(SELECT * FROM setting WHERE group = 1 AND user = 2))
AS temp
I think I'm probably going to have to suck it up and do some custom query writing, instead of relying on anything that the Django ORM provides me out of the box...but I'm more than happy to be wrong about that.
Issue 2 (the bigger one): How in the heck do I actually do this? A ForeignKey relationship doesn't seem to give me a way to customize the fields that are pulled in when doing the reverse lookup, at least not in any way that I've been able to find in a day or so of stumbling around. I have a feeling that a custom reverse manager is almost certainly what I'm looking for, but I haven't actually figured out how to use it in the context of a model, and in particular a model that's having it's downstream views autogenerated by DRF.
Any help appreciated!