Django外键不适用于一对多关系

Posted

技术标签:

【中文标题】Django外键不适用于一对多关系【英文标题】:Django foreign key not working for One-To-Many relationship 【发布时间】:2016-11-16 00:19:09 【问题描述】:

我正在尝试编写一个查询,当搜索艺术家 ID 时,该艺术家的信息及其所有作品都是结果,基本上是 ArtistArtistPiece 之间的连接查询

#models.py
class Artist(models.Model):
    name = models.CharField(max_length=100)
    artist = models.CharField(max_length=150)
    created_by = models.ForeignKey(User)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class ArtistPiece(models.Model):
    artist = models.ForeignKey(Artist, on_delete = models.CASCADE)
    piece_name = models.CharField(max_length=50)
    details = models.CharField(max_length=100)
#views.py
from .models import Artist, ArtistPiece

class EditArtistViewSet(viewsets.ViewSet):

    def edit(self,request,artist_id):
        artist = Artist.objects.select_related().get(pk=artist_id)
        data = model_to_dict(artist)
        return render(
            request, 'ArtistInfo/edit.html', 
                'editing': 'true',
                'edit_data': json.dumps(data),
            ) 

    def submit_edit(self,request):
        return render(request, 'ArtistInfo/edit.html')

上述方法有效,但它不会从 ArtistPiece 模型中选择任何数据,尽管有主键。然后在阅读this post 关于使用select_related 之后,我意识到与其查找艺术家,不如通过foreign_key 查找ArtistPiece,并使用select_related 查找有关艺术家的信息。

然后我尝试了这个

def edit(self, request, artist_id):
    artist = ArtistPiece.objects.get()
    data = model_to_dict(artist)

这导致了以下错误get() 返回了多个 ArtistPiece -- 它返回了 5!。搜索,我发现this post 表明我需要使用过滤器而不是获取。然后我尝试了这个

def edit(self, request, artist_id):
    artist = ArtistPiece.objects.select_related('artist').filter(artist=artist_id)
    data = model_to_dict(artist)

这给出了以下错误'QuerySet' object has no attribute '_meta'。我尝试搜索这个错误,发现 this 基本上建议使用 get,这似乎与我发现的所有其他内容背道而驰。

总而言之,我只想选择一位艺术家和他们的作品,但我似乎无法弄清楚如何。

编辑 - 我尝试了一些方法并取得了一些进展,但仍然无法正常工作

为了清楚起见,我正在尝试编写一个查询,该查询将通过他们的 id 查找艺术家,结果将是艺术家的信息和艺术家的作品。我可以根据艺术家 ID 或 ArtistPiece 模型查询和检索 Artist 模型,但没有一个查询会同时返回 Artist 和与该艺术家关联的所有 ArtistPiece 条目。

按照@bignose 的建议将related_name='pieces' 添加到我的模型中,然后我尝试了artist = Artist.objects.select_related('pieces').filter(pk=artist_id),但仍然给出了no 属性.... 上面的错误。然后我将 data = model_to_dict(artist) 更改为 data = [model_to_dict(a) for a in artist] 并且它起作用了,但是数据只是艺术家,ArtistPiece 模型中没有任何数据。

我没有查询Artist 模型,而是尝试查询ArtistPiece 模型:artist = ArtistPiece.objects.select_related('artist').filter(artist=artist_id),但是只返回了艺术家的作品,没有来自Artist 模型的信息。

【问题讨论】:

我已将ArtistPiece的名称修改为单数;该名称应反映每个实例代表其中 一个 的事实。 【参考方案1】:

model_to_dict 接受单个模型对象,但您正在将QuerySet 类型的对象传递给该对象(与列表非常相似)。要获取所有对象的字典列表,您需要在每个模型对象上显式调用model_to_dict,例如:

data = [model_to_dict(a) for a in artist]

更好的方法是使用QuerySet.values()

data = artist.values()

根据Queryset.Values() document:

当用作可迭代对象时,返回一个返回字典而不是模型实例的 QuerySet。

这些字典中的每一个都代表一个对象,其键对应于模型对象的属性名称。

还可以查看Serializer 类。我认为它对你有用。

【讨论】:

这部分有效。我可以查询Artist 模型或ArtistPiece 模型,但我似乎无法使用外键获得“组合”查询。我在上面编辑了我的帖子以显示更改。谢谢【参考方案2】:

ArtistPiece.objects.filter(artist=artist_id),这将返回一个查询集。 如果你想要一个列表,你可以做ArtistPiece.objects.filter(artist=artist_id).values_list('id', flat=True) https://docs.djangoproject.com/en/1.10/ref/models/querysets/#values-list

【讨论】:

如果这不是您想要的,请告诉我 第一个查询有效,但它只返回该艺术家 ID 的 ArtistPiece 条目,而不是同时返回 ArtistArtistPiece。第二个返回如下错误'int' object has no attribute '_meta'【参考方案3】:

ForeignKey 字段类型也会自动在外部模型上设置一个属性;在你的情况下,Artist.artistpieces_set

favourite_artist = Artist.objects.get(pk="foo")  # However you get an Artist instance.
favourite_artist.artistpieces_set  # Is a QuerySet of all the ArtistPiece instances that reference this instance.

# Because it's a QuerySet, you can iterate it, filter it, etc.
for piece in favourite_artist.artistpieces_set.all():
    put_in_exhibition(piece)

因此,当您获得 Artist 实例时,它会自动具有一个属性,即 QueryManager 用于引用 ArtistArtistPiece 实例。

这很好,因为这意味着外键关系是在一个地方定义的,但也可以从另一端访问。

有关如何使用这些功能,请参阅“Following relationships “backwards””的文档。

【讨论】:

当我尝试这个favourite_artist = Artist.objects.get(pk="foo") 时,艺术家被返回,但favourite_artist.pieces 抛出一个错误,指出'QuerySet' object has no attribute 'pieces'。我的模型中肯定有相关名称。 该消息告诉您您有一个 QuerySet 实例,而不是 Artist 实例。仔细检查您是如何获取对象的。 我做了一些更改并取得了一些进展,但仍然无法正常工作。我从模型中删除了related_name='pieces',也将favourite_artist.pieces 设为单数,所以现在是favourite_artist.piece,我注意到这是Django documentation 显示的方式。但是我现在收到错误'RelatedManager' object is not iterable 感谢您的帮助,但我想我可能误解了这些搜索的工作原理。我来自 Cakephp/Laravel 背景,对此的查询将返回同一对象中的 Artist 和 ArtistPiece。例如:Artist : 'name' : 'some_name'...., 'ArtistPiece' : 'piece_name' : 'name', ...。对 Django 来说是这样吗,或者在这种情况下,查询Artist 并设置一个变量,然后在查询ArtistPiece 后设置一个单独的变量是否是标准做法?

以上是关于Django外键不适用于一对多关系的主要内容,如果未能解决你的问题,请参考以下文章

转: django数据库操作-增删改查-多对多关系以及一对多(外键)关系

如何借助一对多关系在 Django 中使用外键从课程中获取主题

Django模型加入一对多关系以在模板中显示

NHibernate 级联删除不适用于一对多关联

django

jango 模型管理数据model,数据库外键主键与一对一,一对多,多对多关系