Sas*_*hua 5 mysql django rest serialization manytomanyfield
我在使用Django-REST包的Django服务器上创建了一个在软件产品构建中建模一组文件的类.设计是应该能够将文件组(一个Depot实例)分配给多个Build实例(例如,使用相同的音频文件库的"alpha"和"beta"构建).但是,在创建库时,它是作为在客户端上创建单个Build的一部分创建的; 只是后来,实用程序脚本才允许将现有的Depot添加到其他Build.
对我来说,Depot类应该用ManyToManyField表示这种关系似乎很自然.问题是序列化程序似乎不知道如何处理这个ManyToManyField.我尝试了几种解决方法,但每种方法都有自己的错误.我试过让我的DepotSerializer成为a rest_framework.serializers.Serializer或a rest_framework.serializers.ModelSerializer,但这似乎与这个问题无关.
Models.py:
class Depot(models.Model):
name = models.CharField(max_length=64)
builds = models.ManyToManyField(Build)
TYPE_EXECUTABLE = 0
TYPE_CORE = 1
TYPE_STREAMING = 2
depot_type = models.IntegerField(choices = (
(TYPE_EXECUTABLE, 'Executable'),
(TYPE_CORE, 'Core'),
(TYPE_STREAMING, 'Streaming'),
))
def __str__(self):
return self.name
Run Code Online (Sandbox Code Playgroud)
Views.py:
class DepotCreate(mixins.CreateModelMixin,
generics.GenericAPIView):
serializer_class = DepotSerializer
queryset = Depot.objects.all()
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
Serializers.py版本1:
class DepotSerializer(serializers.ModelSerializer):
builds = serializers.PrimaryKeyRelatedField()
class Meta:
model = Depot
fields = ('id', 'name', 'builds', 'depot_type')
read_only_fields = ('id',)
def validate(self, attrs):
build = attrs['builds']
if build == None:
raise serializers.ValidationError("Build could not be found")
for depot in build.depot_set.all():
if depot.name == attrs['name']:
raise serializers.ValidationError("Build already contains a depot \"{}\"".format(depot.name))
return attrs
def restore_object(self, attrs, instance=None):
# existence of the build has already been validated
return Depot(**attrs)
Run Code Online (Sandbox Code Playgroud)
此版本在Depot init调用期间导致以下错误:
Exception Type: TypeError
Exception Value:
'builds' is an invalid keyword argument for this function
Exception Location: /webapps/cdp_admin_django/lib/python3.4/site-packages/django/db/models/base.py in __init__, line 417
Run Code Online (Sandbox Code Playgroud)
这似乎表明Depot模型无法处理'builds'参数,尽管它有一个'builds'ManyToManyField成员.
Serializers.py'recovery_object'ver 2:
def restore_object(self, attrs, instance=None):
# existence of the build has already been validated
build = attrs['builds']
depotObj = Depot(name=attrs['name'], depot_type=attrs['depot_type'])
depotObj.builds.add(build)
return depotObj
Run Code Online (Sandbox Code Playgroud)
这给了我错误:
Exception Type: ValueError
Exception Value:
"<Depot: depot_test4>" needs to have a value for field "depot" before this many-to-many relationship can be used.
Exception Location: /webapps/cdp_admin_django/lib/python3.4/site-packages/django/db/models/fields/related.py in __init__, line 524
Run Code Online (Sandbox Code Playgroud)
经过相当多的调查后,我发现如果在尝试操作该字段之前没有保存MYSQL条目,ManyToMany关系会给你带来麻烦.因此,restore_object ver 3:
def restore_object(self, attrs, instance=None):
# existence of the build has already been validated
build = attrs['builds']
depotObj = Depot(name=attrs['name'], depot_type=attrs['depot_type'])
depotObj.save()
depotObj.builds.add(build)
return depotObj
Run Code Online (Sandbox Code Playgroud)
这确实为此实例成功创建了表条目,但最终会抛出以下错误:
Exception Type: IntegrityError
Exception Value:
(1062, "Duplicate entry '5' for key 'PRIMARY'")
Exception Location: /webapps/cdp_admin_django/lib/python3.4/site-packages/MySQLdb/connections.py in defaulterrorhandler, line 38
Run Code Online (Sandbox Code Playgroud)
在rest_framework/mixins.py调用serializer.save(force_insert = True)期间发生此错误.看起来它应该强制创建一个新的表条目,可能不同意我之前对Model.save的调用.
有谁知道这样的设计的正确方法?我觉得这不是桌面结构的不寻常之处.
编辑10/20/2014: 在下面的建议之后,我尝试为我的一个模型编写一个新的ModelSerializer; 在很大程度上是因为这些类型的操作顺序问题,我放弃了使用ModelSerializer并通过读取serializer.data在views.py中完成了所有数据到对象的字段处理.
在ModelSerializer DID帮助中有一个PrimaryKeyRelatedField(many = True).值得注意的是,我能够使用现有模型创建一个序列化程序实例,并获得正确的serializer.data.但是,我仍然遇到这样的问题:除了创建一个新的模型实例并传递ManyToManyField值之外,restore_object可以执行所有操作.我仍然得到"TypeError:'[PrimaryKeyRelatedField name]'是这个函数的无效关键字参数"如果我将该字段传递给模型的init func.在REST库本身之前,我仍然无法保存模型.此外,在此模式下,序列化程序使用Model的值填充serializer.data,而不是数据输入中提供的值.因此,如果您不在restore_object中使用PrimaryKeyRelatedField的attrs值,则会将其丢弃.
看来我需要将ModelSerializer.save重写为某种预保存,应用ManyToMany输入和后保存,但我需要attrs值,以便我可以在那时应用和修改ManyToManyField.我意识到序列化程序确实有init_data字段来查看原始输入,但是在使用序列化程序将数据列表反序列化为新对象列表的情况下,我认为没有办法跟踪哪个serializer.init_data对应于哪个serializer.object.
小智 1
在序列化器版本 1 中,您不必添加
构建=serializers.PrimaryKeyRelatedField()
因为模型序列化器将为您创建它。事实上,如果您查看文档的示例(http://www.django-rest-framework.org/api-guide/relations/),您会发现当存在 FK 'to' 时,将应用 PrimaryKeyRelatedField当前模型(不是 M2M 关系)。
我会将其从序列化器中删除,然后看看发生了什么。