#django #django-rest-framework #many-to-many #django-intermediate-table
#django #django-rest-framework #многие ко многим #django-промежуточная таблица
Вопрос:
Django не управляет нашими базами данных для нас, поэтому я создал таблицу, RulesetRuleMap
чтобы обрабатывать ManyToMany
отношения между Ruleset
и Rule
: каждый Ruleset
может состоять из нескольких Rules
, и каждый Rule
может использоваться в нескольких Rulesets
.
Модели
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'
Сериализаторы
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
На домашней странице пользователь может добавлять / изменять Ruleset
и добавлять / модифицировать ассоциированное Rules
. При отправке мы получаем полезную нагрузку, подобную этой:
{
"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"
}
]
}
Как описано в Djange REST Framework, я определил пользовательский create()
для вложенных RulesetSerializer
для обработки создания нескольких объектов. Согласно Django, нужно уметь
используйте add(), create() или set() для создания связей, если вы указываете through_defaults для любых обязательных полей.
При выполнении ruleset.rules.add(*rules_storage, through_defaults={})
я получаю ошибку
{TypeError}add() got an unexpected keyword argument 'through_defaults'
При выполнении ruleset.rules.add(*rules_storage)
я получаю ошибку
{AttributeError}Cannot use add() on a ManyToManyField which specifies an intermediary model.Use database_models.TcRulesetRuleMap's Manager instead.
Есть ли ошибка в моей модели и / или настройке сериализатора или есть ошибка в django?
Ответ №1:
Как там сказано:
Невозможно использовать add() для ManyToManyField, который определяет промежуточную модель.
Вы указали свою собственную сквозную модель, RulesetRuleMap
поэтому вам нужно создать объекты самостоятельно, потому что django не поддерживает add()
этот сценарий.
Если вы хотите использовать add()
, create()
или set()
, то, согласно документации, приведенной ниже, вам необходимо передать kwarg through_defaults
для любых обязательных полей. У вас нет дополнительных обязательных полей, поэтому потребуется отладка на вашем конкретном наборе моделей.
Документы DRF для этой взаимосвязи с сквозной моделью находятся здесь
В документах django есть хороший пример для настройки объектов с помощью сквозной модели здесь
В примере есть 3 модели, Person
, Group
и Membership
. Group
имеет M2M для Person
прохождения Membership
.
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<Group: The Beatles>]>
>>> m2 = Membership.objects.create(person=paul, group=beatles,
... date_joined=date(1960, 8, 1),
... invite_reason="Wanted to form a band.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
Комментарии:
1. Пожалуйста, объясните разницу между моделями django и моей @markwalker_ . В связанном примере django также указана его собственная сквозная модель, и в нем можно использовать add(), create() или set(). Набор правил -> Членство, Правило -> Лицо, Набор правил -> Группа
2. На самом деле разницы в моделях нет. Они определяют две модели, которые связаны с M2M через пользовательскую модель, а не с волшебной моделью django M2M, как и вы.
Rule
похожеPerson
,Ruleset
похожеGroup
иRulesetRuleMap
похожеMembership
. Вы правы — документы также показывают, как вы можете использовать некоторые встроенные методы, такие какadd()
, и у вас нет дополнительных обязательных полей, поэтому непонятно, почему у django проблема с тем, что вы делаете, без дополнительной отладки вашего конкретного сценария
Ответ №2:
Я неправильно прочитал документы django. Я работаю на django 2.1, а сквозные поля были введены только в 2.2.