【问题标题】:Cannot resolve keyword 'get_album_detail' into field无法将关键字“get_album_detail”解析为字段
【发布时间】:2021-02-06 23:06:36
【问题描述】:

我正在尝试创建一个可以获取艺术家姓名和歌曲名称的搜索字段,但我收到错误消息“无法将关键字 'get_full_album_detail' 解析到字段中。”一旦我尝试从“get_album_detail”查询。

 class Artist(models.Model):
    user            =   models.OneToOneField(User, on_delete=models.CASCADE)
    username        =   models.CharField(max_length=50, null=True, unique=True)



class Album(models.Model):
        artist      =   models.ForeignKey(Artist, on_delete=models.CASCADE)
        name        =   models.CharField(max_length=120)

    @property
    def get_album_detail(self):
        return str(self.artist.username) + " - " + str(self.name)



   ### CUSTOM MODEL MANAGER
class SongQuerySet(models.QuerySet):
    def search(self, query = None):
        qs = self
        if query is not None:
            or_lookup = (Q(get_album_detail__icontains=query)|
                Q(slug__icontains=query)
                #Q(artist__user__icontains=query)
                )
            qs = qs.filter(or_lookup).distinct()
        return qs

## SEARCH VIEW
class AlbumSearch(ListView):
    template_name   =   'search/song_search.html'
    paginate_by     =   15  

    def get_queryset(self):
        request =   self.request
        query = request.GET.get('q', None)
        if query is not None:
            song_result   =   Song.objects.search(query=query)
            return song_result

【问题讨论】:

  • get_album_detail 不是一个字段。它不存储在数据库中,因此您无法对此进行查询。

标签: django django-models django-views django-orm django-managers


【解决方案1】:

get_album_detail 不是一个字段,它是一个属性。这意味着它是在 Django/Python 层确定的,因此数据库无法对其进行过滤,因为数据库不知道 Django/Python 层。

您可以使用.annotate(…) [Django-doc] 来“派生”查询中的字段,然后对其进行过滤。在这种情况下,我们可以使用Concat [Django-doc]

from django.db.models import Value
from django.db.models.functions import Concat

# …

def search(self, query = None):
    qs = self
    if query is not None:
        or_lookup = (
            Q(album_detail__icontains=query) |
            Q(slug__icontains=query)    
        )
        qs = qs.annotate(
            album_detail=Concat('artist__username', Value(' - '), 'name')
        ).filter(or_lookup).distinct()
    return qs

【讨论】:

  • 虽然这在技术上是正确的,但不建议这样做。计算的字符串用于查询与用户名和名称的组合相同的目的。这些字段可以被索引。这个 concat 永远不能被索引。事实上,我更愿意将非规范化为查找模型,而不是像这样进行连接。当至少提供一个组件作为搜索查询时,应使用 Concat。
  • @Melvyn:如果查询范围是foo - bar,那么这可能意味着多种情况:foo 是艺术家,bar 是名称,或者艺术家以某种方式拥有@987654330 @。在多个字段上使用__icontains 搜索确实不是一个好主意。这主要是因为搜索,即使是在前缀树上,计算量也很大。为了匹配元素,应该使用诸如生成片段的弹性搜索之类的技术,并使用允许错字的“模糊” FSM 进行搜索。
  • 我的意思是,您可以在' - '上拆分查找,然后filter(artist__username=split[0], name=split[1]) 并在过滤后构建注释。也就是说 - 如果您仍然需要注释并且我认为您可能不再需要它。
  • @Melvyn:不,如果你通过拆分,它应该是.filter(artist__username__iendswith=split[0], name__istartswith=split[1]),尤其是__endswith,除非有一些高级索引机制,比如后缀树,否则会导致性能下降。这也是从软件设计的角度来看,如果案例会更复杂,很难得到完全正确的细节。
  • Melvyn:但实际上首先在数据库上“搜索”并不是一个好主意。数据库不是为了像搜索引擎那样执行搜索而构建的。这更多的是检索、连接、聚合和存储项目。人们需要更高级的技术,例如 n-grams 来实现良好的搜索。令人遗憾的是,Django 文档没有提及太多,它从未真正说__icontains 是一种很好的搜索方式,但也没有说明如何有效地进行搜索。
猜你喜欢
  • 2018-11-23
  • 2011-06-09
  • 1970-01-01
  • 1970-01-01
  • 2021-05-23
  • 2013-10-09
  • 2019-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多