#32011 closed Bug (invalid)
Error when calling add() on ManyRelatedManager with intermediary model
| Reported by: | Philipp Maino | Owned by: | nobody |
|---|---|---|---|
| Component: | Documentation | Version: | 2.1 |
| Severity: | Normal | Keywords: | ManyToMany, ManyRelatedManager |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Django is not managing our databases for us, therefor I created the table RulesetRuleMap to handle the ManyToMany relationship between Ruleset and Rule: Each Ruleset can consist of multiple Rules and each Rule can be used in multiple Rulesets.
Models
class Rule(models.Model):
id = models.BigAutoField(primary_key=True)
percentage_of_total = models.FloatField(blank=False, null=False)
_rule_parameter = models.ForeignKey('RuleParameter', models.DO_NOTHING, blank=False, null=False)
class Meta:
managed = False
db_table = '_rule'
class Ruleset(models.Model):
id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=300, blank=False, null=False)
description = models.CharField(max_length=300, blank=False, null=False)
rules = models.ManyToManyField('Rule', through="RulesetRuleMap")
class Meta:
managed = False
db_table = '_ruleset'
class RulesetRuleMap(models.Model):
id = models.BigAutoField(primary_key=True)
_rule = models.ForeignKey('Rule', models.CASCADE)
_ruleset = models.ForeignKey('Ruleset', models.CASCADE)
class Meta:
managed = False
db_table = '_ruleset_rule_map'
Serializers
class RulesetRuleMapSerializer(serializers.ModelSerializer):
class Meta:
model = db_models.RulesetRuleMap
fields = '__all__'
class RuleSerializer(serializers.ModelSerializer):
class Meta:
model = db_models.Rule
fields = '__all__'
class RulesetSerializer(serializers.ModelSerializer):
rules = RuleSerializer(many=True)
class Meta:
model = db_models.Ruleset
fields = '__all__'
def create(self, validated_data):
rules_data = validated_data.pop('rules')
ruleset = db_models.Ruleset.objects.create(**validated_data)
rules_storage =[]
for rule_data in rules_data:
rule, created = db_models.Rule.objects.get_or_create(**rule_data)
rules_storage.append(rule)
ruleset.rules.add(*rules_storage, through_defaults={})
return ruleset
On a homepage the user can add/modify a Ruleset and add/modify the assosiated Rules. On submission we receive a payload like this:
{
"id": None,
"name": "Split_50.0_Param1_50.0_Param2",
"description": "test",
"rules": [
{
"id": None,
"percentage_of_total": "50",
"tc_rule_parameter": "3"
},
{
"id": None,
"percentage_of_total": "50",
"tc_rule_parameter": "2"
}
]
}
As described in DRF I defined a custom create() for the nested RulesetSerializer to handle the creation of multiple objects. According to / Django one should be able to
use add(), create(), or set() to create relationships, as long as you specify through_defaults for any required fields.
When executing ruleset.rules.add(*rules_storage, through_defaults={}) I get the error
{TypeError}add() got an unexpected keyword argument 'through_defaults
When executing ruleset.rules.add(*rules_storage) I get the error
{AttributeError}Cannot use add() on a ManyToManyField which specifies an intermediary model.Use database_models.TcRulesetRuleMap's Manager instead.
Is there a mistake in my model and/or serializer set up or is there a bug in django?
Change History (2)
follow-up: 2 comment:1 by , 5 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
comment:2 by , 5 years ago
Replying to felixxm:
through_defaultswas added in Django 2.2, please use documentation for the version you're using.
Hi @felixxm, I'm very happy if that's the problem at hand. I scaned over the docs for 2.1 and didn't this difference:
3.1
You can also use add(), create(), or set() to create relationships, as long as you specify through_defaults for any required fields
2.1
Unlike normal many-to-many fields, you can’t use add(), create(), or set() to create relationships:
through_defaultswas added in Django 2.2, please use documentation for the version you're using.