Django - ManyToMany through synthetic relation fields











up vote
0
down vote

favorite












I have such models in my application:



class User(AbstractUser):
pass


class MyObject(models.Model):
name = models.CharField(max_length=200, unique=False, db_index=True)

related_users = models.ManyToManyField(
User, through='RelatedUsers', related_name='related_users'
)


class RelatedUsers(models.Model):
my_object = models.ForeignKey(
MyObject, related_name='my_object_related_users'
)
user = models.ForeignKey(User)
type = models.CharField(
max_length=100,
choices=RelatedUsersTypes.choices()
)

class Meta:
unique_together = ('user', 'my_object', 'type')


class FunctionalityRelatedUsersTypes(BaseChoiceEnum):
TYPE_1 = 'TYPE 1'
TYPE_2 = 'TYPE 2'
TYPE_3 = 'TYPE 3'
TYPE_4 = 'TYPE 4'
TYPE_5 = 'TYPE 5'


I'm wondering if there is an option to create some kind of synthetic relations on MyObject.
I would like to be able to get users by type using one field, example: related_users_type_1. I'd like to use it in DRF serializer as well (so I can pass just List of ids, and relation will create a Proxy object with the corresponding type).



Pseudocode:



related_users_type_1 = models.RelationField(RelatedUsers, filter={'type': 'TYPE_1'})


Sample payload I want to send:



{
"related_users_type_1": [1, 2, 3],
"related_users_type_2": [3]
}


Expected result:




  • 3 RelatedUsers with TYPE_1

  • 1 RelatedUser with TYPE_2










share|improve this question




















  • 1




    Name your classes with singular nouns! RelatedUser instead of RelatedUsers, and so on. This is a best-practice naming convention. When you instantiate an object of the class you're creating a new RelatedUser, just a single one, not many of them.
    – cezar
    6 hours ago












  • Are you just looking to create a structure to label relationships between users and be able to use that relationship as a filter? I;m having a little bit of trouble understanding...
    – robotHamster
    6 hours ago










  • Main purpose is simplifying API request/responses, so user does not have to pass list of structures with user_id and type to related_users field in payload. He passes just list of ids to related_users_type_1, and he can update only users with TYPE_1 via patch (doesn't have to send whole list of already existing users of other types)
    – Blejwi
    6 hours ago










  • working on an answer... it's pretty simple to the point where I still feel like I don't understand the whole picture...
    – robotHamster
    6 hours ago










  • Updated my answer, hopefully this helps you out :)
    – robotHamster
    5 hours ago















up vote
0
down vote

favorite












I have such models in my application:



class User(AbstractUser):
pass


class MyObject(models.Model):
name = models.CharField(max_length=200, unique=False, db_index=True)

related_users = models.ManyToManyField(
User, through='RelatedUsers', related_name='related_users'
)


class RelatedUsers(models.Model):
my_object = models.ForeignKey(
MyObject, related_name='my_object_related_users'
)
user = models.ForeignKey(User)
type = models.CharField(
max_length=100,
choices=RelatedUsersTypes.choices()
)

class Meta:
unique_together = ('user', 'my_object', 'type')


class FunctionalityRelatedUsersTypes(BaseChoiceEnum):
TYPE_1 = 'TYPE 1'
TYPE_2 = 'TYPE 2'
TYPE_3 = 'TYPE 3'
TYPE_4 = 'TYPE 4'
TYPE_5 = 'TYPE 5'


I'm wondering if there is an option to create some kind of synthetic relations on MyObject.
I would like to be able to get users by type using one field, example: related_users_type_1. I'd like to use it in DRF serializer as well (so I can pass just List of ids, and relation will create a Proxy object with the corresponding type).



Pseudocode:



related_users_type_1 = models.RelationField(RelatedUsers, filter={'type': 'TYPE_1'})


Sample payload I want to send:



{
"related_users_type_1": [1, 2, 3],
"related_users_type_2": [3]
}


Expected result:




  • 3 RelatedUsers with TYPE_1

  • 1 RelatedUser with TYPE_2










share|improve this question




















  • 1




    Name your classes with singular nouns! RelatedUser instead of RelatedUsers, and so on. This is a best-practice naming convention. When you instantiate an object of the class you're creating a new RelatedUser, just a single one, not many of them.
    – cezar
    6 hours ago












  • Are you just looking to create a structure to label relationships between users and be able to use that relationship as a filter? I;m having a little bit of trouble understanding...
    – robotHamster
    6 hours ago










  • Main purpose is simplifying API request/responses, so user does not have to pass list of structures with user_id and type to related_users field in payload. He passes just list of ids to related_users_type_1, and he can update only users with TYPE_1 via patch (doesn't have to send whole list of already existing users of other types)
    – Blejwi
    6 hours ago










  • working on an answer... it's pretty simple to the point where I still feel like I don't understand the whole picture...
    – robotHamster
    6 hours ago










  • Updated my answer, hopefully this helps you out :)
    – robotHamster
    5 hours ago













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have such models in my application:



class User(AbstractUser):
pass


class MyObject(models.Model):
name = models.CharField(max_length=200, unique=False, db_index=True)

related_users = models.ManyToManyField(
User, through='RelatedUsers', related_name='related_users'
)


class RelatedUsers(models.Model):
my_object = models.ForeignKey(
MyObject, related_name='my_object_related_users'
)
user = models.ForeignKey(User)
type = models.CharField(
max_length=100,
choices=RelatedUsersTypes.choices()
)

class Meta:
unique_together = ('user', 'my_object', 'type')


class FunctionalityRelatedUsersTypes(BaseChoiceEnum):
TYPE_1 = 'TYPE 1'
TYPE_2 = 'TYPE 2'
TYPE_3 = 'TYPE 3'
TYPE_4 = 'TYPE 4'
TYPE_5 = 'TYPE 5'


I'm wondering if there is an option to create some kind of synthetic relations on MyObject.
I would like to be able to get users by type using one field, example: related_users_type_1. I'd like to use it in DRF serializer as well (so I can pass just List of ids, and relation will create a Proxy object with the corresponding type).



Pseudocode:



related_users_type_1 = models.RelationField(RelatedUsers, filter={'type': 'TYPE_1'})


Sample payload I want to send:



{
"related_users_type_1": [1, 2, 3],
"related_users_type_2": [3]
}


Expected result:




  • 3 RelatedUsers with TYPE_1

  • 1 RelatedUser with TYPE_2










share|improve this question















I have such models in my application:



class User(AbstractUser):
pass


class MyObject(models.Model):
name = models.CharField(max_length=200, unique=False, db_index=True)

related_users = models.ManyToManyField(
User, through='RelatedUsers', related_name='related_users'
)


class RelatedUsers(models.Model):
my_object = models.ForeignKey(
MyObject, related_name='my_object_related_users'
)
user = models.ForeignKey(User)
type = models.CharField(
max_length=100,
choices=RelatedUsersTypes.choices()
)

class Meta:
unique_together = ('user', 'my_object', 'type')


class FunctionalityRelatedUsersTypes(BaseChoiceEnum):
TYPE_1 = 'TYPE 1'
TYPE_2 = 'TYPE 2'
TYPE_3 = 'TYPE 3'
TYPE_4 = 'TYPE 4'
TYPE_5 = 'TYPE 5'


I'm wondering if there is an option to create some kind of synthetic relations on MyObject.
I would like to be able to get users by type using one field, example: related_users_type_1. I'd like to use it in DRF serializer as well (so I can pass just List of ids, and relation will create a Proxy object with the corresponding type).



Pseudocode:



related_users_type_1 = models.RelationField(RelatedUsers, filter={'type': 'TYPE_1'})


Sample payload I want to send:



{
"related_users_type_1": [1, 2, 3],
"related_users_type_2": [3]
}


Expected result:




  • 3 RelatedUsers with TYPE_1

  • 1 RelatedUser with TYPE_2







python django django-rest-framework






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 6 hours ago









Rohit Verma

1,4372623




1,4372623










asked 6 hours ago









Blejwi

358417




358417








  • 1




    Name your classes with singular nouns! RelatedUser instead of RelatedUsers, and so on. This is a best-practice naming convention. When you instantiate an object of the class you're creating a new RelatedUser, just a single one, not many of them.
    – cezar
    6 hours ago












  • Are you just looking to create a structure to label relationships between users and be able to use that relationship as a filter? I;m having a little bit of trouble understanding...
    – robotHamster
    6 hours ago










  • Main purpose is simplifying API request/responses, so user does not have to pass list of structures with user_id and type to related_users field in payload. He passes just list of ids to related_users_type_1, and he can update only users with TYPE_1 via patch (doesn't have to send whole list of already existing users of other types)
    – Blejwi
    6 hours ago










  • working on an answer... it's pretty simple to the point where I still feel like I don't understand the whole picture...
    – robotHamster
    6 hours ago










  • Updated my answer, hopefully this helps you out :)
    – robotHamster
    5 hours ago














  • 1




    Name your classes with singular nouns! RelatedUser instead of RelatedUsers, and so on. This is a best-practice naming convention. When you instantiate an object of the class you're creating a new RelatedUser, just a single one, not many of them.
    – cezar
    6 hours ago












  • Are you just looking to create a structure to label relationships between users and be able to use that relationship as a filter? I;m having a little bit of trouble understanding...
    – robotHamster
    6 hours ago










  • Main purpose is simplifying API request/responses, so user does not have to pass list of structures with user_id and type to related_users field in payload. He passes just list of ids to related_users_type_1, and he can update only users with TYPE_1 via patch (doesn't have to send whole list of already existing users of other types)
    – Blejwi
    6 hours ago










  • working on an answer... it's pretty simple to the point where I still feel like I don't understand the whole picture...
    – robotHamster
    6 hours ago










  • Updated my answer, hopefully this helps you out :)
    – robotHamster
    5 hours ago








1




1




Name your classes with singular nouns! RelatedUser instead of RelatedUsers, and so on. This is a best-practice naming convention. When you instantiate an object of the class you're creating a new RelatedUser, just a single one, not many of them.
– cezar
6 hours ago






Name your classes with singular nouns! RelatedUser instead of RelatedUsers, and so on. This is a best-practice naming convention. When you instantiate an object of the class you're creating a new RelatedUser, just a single one, not many of them.
– cezar
6 hours ago














Are you just looking to create a structure to label relationships between users and be able to use that relationship as a filter? I;m having a little bit of trouble understanding...
– robotHamster
6 hours ago




Are you just looking to create a structure to label relationships between users and be able to use that relationship as a filter? I;m having a little bit of trouble understanding...
– robotHamster
6 hours ago












Main purpose is simplifying API request/responses, so user does not have to pass list of structures with user_id and type to related_users field in payload. He passes just list of ids to related_users_type_1, and he can update only users with TYPE_1 via patch (doesn't have to send whole list of already existing users of other types)
– Blejwi
6 hours ago




Main purpose is simplifying API request/responses, so user does not have to pass list of structures with user_id and type to related_users field in payload. He passes just list of ids to related_users_type_1, and he can update only users with TYPE_1 via patch (doesn't have to send whole list of already existing users of other types)
– Blejwi
6 hours ago












working on an answer... it's pretty simple to the point where I still feel like I don't understand the whole picture...
– robotHamster
6 hours ago




working on an answer... it's pretty simple to the point where I still feel like I don't understand the whole picture...
– robotHamster
6 hours ago












Updated my answer, hopefully this helps you out :)
– robotHamster
5 hours ago




Updated my answer, hopefully this helps you out :)
– robotHamster
5 hours ago












1 Answer
1






active

oldest

votes

















up vote
0
down vote













From the comments we've had, I think your problem can be solved with models as such:



# just for completeness. should probably use an actual user model
class User (models.Model):
name = models.CharField(max_length=64)

class MyObject(models.Model):
name = models.CharField(max_length=64)
users = models.ManyToMany(User, through='MyObjectUsers', symmetrical=False)

def add_relations(self, relations):
for key, list in relations.items():
for id in list:
users.add(user=User.objects.get(pk=id), rel_type=key)



class MyObjectUsers(models.Model):
REL_TYPE_CHOICES=(
('TYPE1','TYPE1'),
('TYPE2','TYPE2')
)
myobject = models.ForeignKey('MyObject', null=True, on_delete=models.SET_NULL)
user = models.ForeignKey('User', null=True, on_delete=models.SET_NULL)
rel_type = models.CharField(max_length=32, choices = REL_TYPE_CHOICES)


The django documentation shows you how to traverse the relationship.



With the above implementation of MyObject, you should be able to to call .add_relations({'TYPE1':[1,2,3]}) on a MyObject instance to create the relationships you need.



I wrote this on my phone so I don't really know if it runs (will test tomorrow)






share|improve this answer























  • Thanks for an answer, but I know how to create such through relationship. For example in SQLAlchemy I can create multiple relationship through same table using primaryjoin. So it would look like: related_users_type_1 = db.relationship('RelatedUsers', primaryjoin='RelatedUsers.type==TYPE_1')
    – Blejwi
    6 hours ago










  • I see what you mean. I think what you are looking for is doable with model managers and/or model methods or some involved logic in the view to implement custom methods such as the ones you are looking for. Will edit the answer to reflect that tomorrow. For now, I need sleep! :P @Blewji
    – robotHamster
    5 hours ago













Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53203298%2fdjango-manytomany-through-synthetic-relation-fields%23new-answer', 'question_page');
}
);

Post as a guest
































1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote













From the comments we've had, I think your problem can be solved with models as such:



# just for completeness. should probably use an actual user model
class User (models.Model):
name = models.CharField(max_length=64)

class MyObject(models.Model):
name = models.CharField(max_length=64)
users = models.ManyToMany(User, through='MyObjectUsers', symmetrical=False)

def add_relations(self, relations):
for key, list in relations.items():
for id in list:
users.add(user=User.objects.get(pk=id), rel_type=key)



class MyObjectUsers(models.Model):
REL_TYPE_CHOICES=(
('TYPE1','TYPE1'),
('TYPE2','TYPE2')
)
myobject = models.ForeignKey('MyObject', null=True, on_delete=models.SET_NULL)
user = models.ForeignKey('User', null=True, on_delete=models.SET_NULL)
rel_type = models.CharField(max_length=32, choices = REL_TYPE_CHOICES)


The django documentation shows you how to traverse the relationship.



With the above implementation of MyObject, you should be able to to call .add_relations({'TYPE1':[1,2,3]}) on a MyObject instance to create the relationships you need.



I wrote this on my phone so I don't really know if it runs (will test tomorrow)






share|improve this answer























  • Thanks for an answer, but I know how to create such through relationship. For example in SQLAlchemy I can create multiple relationship through same table using primaryjoin. So it would look like: related_users_type_1 = db.relationship('RelatedUsers', primaryjoin='RelatedUsers.type==TYPE_1')
    – Blejwi
    6 hours ago










  • I see what you mean. I think what you are looking for is doable with model managers and/or model methods or some involved logic in the view to implement custom methods such as the ones you are looking for. Will edit the answer to reflect that tomorrow. For now, I need sleep! :P @Blewji
    – robotHamster
    5 hours ago

















up vote
0
down vote













From the comments we've had, I think your problem can be solved with models as such:



# just for completeness. should probably use an actual user model
class User (models.Model):
name = models.CharField(max_length=64)

class MyObject(models.Model):
name = models.CharField(max_length=64)
users = models.ManyToMany(User, through='MyObjectUsers', symmetrical=False)

def add_relations(self, relations):
for key, list in relations.items():
for id in list:
users.add(user=User.objects.get(pk=id), rel_type=key)



class MyObjectUsers(models.Model):
REL_TYPE_CHOICES=(
('TYPE1','TYPE1'),
('TYPE2','TYPE2')
)
myobject = models.ForeignKey('MyObject', null=True, on_delete=models.SET_NULL)
user = models.ForeignKey('User', null=True, on_delete=models.SET_NULL)
rel_type = models.CharField(max_length=32, choices = REL_TYPE_CHOICES)


The django documentation shows you how to traverse the relationship.



With the above implementation of MyObject, you should be able to to call .add_relations({'TYPE1':[1,2,3]}) on a MyObject instance to create the relationships you need.



I wrote this on my phone so I don't really know if it runs (will test tomorrow)






share|improve this answer























  • Thanks for an answer, but I know how to create such through relationship. For example in SQLAlchemy I can create multiple relationship through same table using primaryjoin. So it would look like: related_users_type_1 = db.relationship('RelatedUsers', primaryjoin='RelatedUsers.type==TYPE_1')
    – Blejwi
    6 hours ago










  • I see what you mean. I think what you are looking for is doable with model managers and/or model methods or some involved logic in the view to implement custom methods such as the ones you are looking for. Will edit the answer to reflect that tomorrow. For now, I need sleep! :P @Blewji
    – robotHamster
    5 hours ago















up vote
0
down vote










up vote
0
down vote









From the comments we've had, I think your problem can be solved with models as such:



# just for completeness. should probably use an actual user model
class User (models.Model):
name = models.CharField(max_length=64)

class MyObject(models.Model):
name = models.CharField(max_length=64)
users = models.ManyToMany(User, through='MyObjectUsers', symmetrical=False)

def add_relations(self, relations):
for key, list in relations.items():
for id in list:
users.add(user=User.objects.get(pk=id), rel_type=key)



class MyObjectUsers(models.Model):
REL_TYPE_CHOICES=(
('TYPE1','TYPE1'),
('TYPE2','TYPE2')
)
myobject = models.ForeignKey('MyObject', null=True, on_delete=models.SET_NULL)
user = models.ForeignKey('User', null=True, on_delete=models.SET_NULL)
rel_type = models.CharField(max_length=32, choices = REL_TYPE_CHOICES)


The django documentation shows you how to traverse the relationship.



With the above implementation of MyObject, you should be able to to call .add_relations({'TYPE1':[1,2,3]}) on a MyObject instance to create the relationships you need.



I wrote this on my phone so I don't really know if it runs (will test tomorrow)






share|improve this answer














From the comments we've had, I think your problem can be solved with models as such:



# just for completeness. should probably use an actual user model
class User (models.Model):
name = models.CharField(max_length=64)

class MyObject(models.Model):
name = models.CharField(max_length=64)
users = models.ManyToMany(User, through='MyObjectUsers', symmetrical=False)

def add_relations(self, relations):
for key, list in relations.items():
for id in list:
users.add(user=User.objects.get(pk=id), rel_type=key)



class MyObjectUsers(models.Model):
REL_TYPE_CHOICES=(
('TYPE1','TYPE1'),
('TYPE2','TYPE2')
)
myobject = models.ForeignKey('MyObject', null=True, on_delete=models.SET_NULL)
user = models.ForeignKey('User', null=True, on_delete=models.SET_NULL)
rel_type = models.CharField(max_length=32, choices = REL_TYPE_CHOICES)


The django documentation shows you how to traverse the relationship.



With the above implementation of MyObject, you should be able to to call .add_relations({'TYPE1':[1,2,3]}) on a MyObject instance to create the relationships you need.



I wrote this on my phone so I don't really know if it runs (will test tomorrow)







share|improve this answer














share|improve this answer



share|improve this answer








edited 5 hours ago

























answered 6 hours ago









robotHamster

698




698












  • Thanks for an answer, but I know how to create such through relationship. For example in SQLAlchemy I can create multiple relationship through same table using primaryjoin. So it would look like: related_users_type_1 = db.relationship('RelatedUsers', primaryjoin='RelatedUsers.type==TYPE_1')
    – Blejwi
    6 hours ago










  • I see what you mean. I think what you are looking for is doable with model managers and/or model methods or some involved logic in the view to implement custom methods such as the ones you are looking for. Will edit the answer to reflect that tomorrow. For now, I need sleep! :P @Blewji
    – robotHamster
    5 hours ago




















  • Thanks for an answer, but I know how to create such through relationship. For example in SQLAlchemy I can create multiple relationship through same table using primaryjoin. So it would look like: related_users_type_1 = db.relationship('RelatedUsers', primaryjoin='RelatedUsers.type==TYPE_1')
    – Blejwi
    6 hours ago










  • I see what you mean. I think what you are looking for is doable with model managers and/or model methods or some involved logic in the view to implement custom methods such as the ones you are looking for. Will edit the answer to reflect that tomorrow. For now, I need sleep! :P @Blewji
    – robotHamster
    5 hours ago


















Thanks for an answer, but I know how to create such through relationship. For example in SQLAlchemy I can create multiple relationship through same table using primaryjoin. So it would look like: related_users_type_1 = db.relationship('RelatedUsers', primaryjoin='RelatedUsers.type==TYPE_1')
– Blejwi
6 hours ago




Thanks for an answer, but I know how to create such through relationship. For example in SQLAlchemy I can create multiple relationship through same table using primaryjoin. So it would look like: related_users_type_1 = db.relationship('RelatedUsers', primaryjoin='RelatedUsers.type==TYPE_1')
– Blejwi
6 hours ago












I see what you mean. I think what you are looking for is doable with model managers and/or model methods or some involved logic in the view to implement custom methods such as the ones you are looking for. Will edit the answer to reflect that tomorrow. For now, I need sleep! :P @Blewji
– robotHamster
5 hours ago






I see what you mean. I think what you are looking for is doable with model managers and/or model methods or some involved logic in the view to implement custom methods such as the ones you are looking for. Will edit the answer to reflect that tomorrow. For now, I need sleep! :P @Blewji
– robotHamster
5 hours ago




















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53203298%2fdjango-manytomany-through-synthetic-relation-fields%23new-answer', 'question_page');
}
);

Post as a guest




















































































Popular posts from this blog

Schultheiß

Verwaltungsgliederung Dänemarks

Liste der Kulturdenkmale in Wilsdruff