我已经对这个问题进行了大量搜索,并在 Stack Overflow 上浏览了一堆相关问题,但似乎没有关于如何“通过”中间模型实现多对多关系的明确答案(或者也许我错过了)。
我有一个名为 Sample 的模型,它与 Region 具有多对多关系。有一个中间模型将两者连接起来,名为 SampleRegion。我目前没有保存关于中间模型的任何额外信息,但我可能会在 future 保存。
这是我的模型:
class Sample(models.Model):
sample_id = models.BigIntegerField(primary_key=True)
description = models.TextField(blank=True)
objects = models.GeoManager()
regions = ManyToManyField(Region, through='SampleRegion')
class Meta:
db_table = u'samples'
def save(self, **kwargs):
# Assign a sample ID only for create requests
if self.sample_id is None:
try: id = Sample.objects.latest('sample_id').sample_id + 1
except Sample.DoesNotExist: id = 1
self.sample_id = id
super(Sample, self).save
class Region(models.Model):
name = models.CharField(max_length=100, unique=True)
def __unicode__(self):
return self.name
class Meta:
db_table = u'regions'
class SampleRegion(models.Model):
sample = models.ForeignKey('Sample')
region = models.ForeignKey(Region)
class Meta:
unique_together = (('sample', 'region'),)
db_table = u'sample_regions'
这是我编写资源的一种方法。这是不正确的,我无法找出正确的方法:
class SampleResource(ModelResource):
regions = fields.ToManyField("tastyapi.resources.RegionResource",
"regions")
class Meta:
queryset = models.Sample.objects.all()
allowed_methods = ['get', 'post', 'put', 'delete']
authentication = ApiKeyAuthentication()
authorization = ObjectAuthorization('tastyapi', 'sample')
excludes = ['user', 'collector']
filtering = {
'version': ALL,
'sesar_number': ALL
}
validation = VersionValidation(queryset, 'sample_id')
def hydrate_regions(self, bundle):
# code to create a new SampleRegion object by getting a list of
# regions from bundle.data['regions']
class RegionResource(ModelResource):
class Meta:
queryset = models.Region.objects.all()
allowed_methods = ['get']
resource_name = "region"
filtering = {
'region': ALL,
}
这就是我发出 POST 请求的方式:
post_data = {
'regions': ["/tastyapi/v1/region/2/"],
'description': 'Created by a test case',
}
client.post('/tastyapi/v1/sample/', data = post_data,
authentication = credentials, format = 'json')
此请求不起作用,因为 bundle.data['regions'] 是
None
到...的时候它到达
hydrate_regions
.有人对我应该如何实现这种情况有任何建议吗?
最佳答案
几天前我想通了这一点。这是我发现的...
如果您没有明确创建中间表,Django 会为您创建 M2M 关系。但是,如果您显式使用中间表,则您负责在中间表中创建记录。为了让它在 Tastypie 中工作,我必须覆盖 save_m2m
方法在中间表中显式创建一条记录,将我刚刚创建的示例和现有区域链接起来。
我的resources.py
的相关部分是这样的现在看起来像:
class SampleResource(ModelResource):
regions = fields.ToManyField("tastyapi.resources.RegionResource",
"regions")
class Meta:
queryset = models.Sample.objects.all()
allowed_methods = ['get', 'post', 'put', 'delete']
authentication = ApiKeyAuthentication()
authorization = ObjectAuthorization('tastyapi', 'sample')
excludes = ['user', 'collector']
filtering = {
'regions': ALL_WITH_RELATIONS,
}
validation = VersionValidation(queryset, 'sample_id')
def save_m2m(self, bundle):
for field_name, field_object in self.fields.items():
if not getattr(field_object, 'is_m2m', False):
continue
if not field_object.attribute:
continue
for field in bundle.data[field_name]:
kwargs = {'sample': models.Sample.objects.get(pk=bundle.obj.sample_id),
'region': field.obj}
try: SampleRegion.objects.get_or_create(**kwargs)
except IntegrityError: continue
class RegionResource(BaseResource):
class Meta:
queryset = models.Region.objects.all()
authentication = ApiKeyAuthentication()
allowed_methods = ['get']
resource_name = "region"
filtering = { 'region': ALL }
关于 Django Tastypie : Imlementing Many To Many "through" relationships,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22601223/