繁体   English   中英

Django 未显示使用带有 select_related 的对象的所有字段

[英]Django not showing up all fields using objects with select_related

我在 Django 中遇到了一个烦人的错误,我不知道该如何解决。

我正在尝试使用 INNER JOIN 显示另一个表中的名称,但无法正常工作。

澄清一下,我有两个数据库canaisAssocformatosAssoc ,我试图从 canaisAssoc 显示 canais 的名称,从 formatosAssoc 显示格式的名称,如果你看一下我的 views.py,我正在使用ajax,因为我需要从模板中的一个 select 中选择一个值来填充其他值,问题是,当我运行 canaisAssoc.objects.select_related('idCanal').filter(idSite_id = site, ativo = True).all ()

如果我运行这个

print(channels.query)

查询的返回是:

SELECT campanhas_canaisassoc id , campanhas_canaisassoc idSite_id , campanhas_canaisassoc idCanal_id , campanhas_canaisassoc ativo , campanhas_canais_dados id , campanhas_canais_dados nomeCanais , campanhas_canais_dados ativo FROM campanhas_canaisassoc INNER JOIN campanhas_canais_dados ON ( campanhas_canaisassoc = idCanal_id ) WHERE campanhas_canaisassoc campanhas_canais_dados ativo True campanhas_canaisassoc id idSite_id 3)

如果我在 phpMyAdmin 中运行它,它们会按预期工作,显示我需要的所有值

id|idSite_id|idCanal_id|ativo|id| 名称Canais |ativo

但是,如果我检查 JSON 的呼叫,他们将返回:

{“频道”:[{“模型”:“campanhas.canaisassoc”,“pk”:14,“字段”:{“idSite”:3,“idCanal”:13,“ativo”:true}},{“模型”:“campanhas.canaisassoc”,“pk”:15,“字段”:{“idSite”:3,“idCanal”:1,“ativo”:true}},{“模型”:“campanhas.canaisassoc” , "pk": 16, "fields": {"idSite": 3, "idCanal": 4, "ativo": true}}, {"model": "campanhas.canaisassoc", "pk": 17, " fields": {"idSite": 3, "idCanal": 10, "ativo": true}}, {"model": "campanhas.canaisassoc", "pk": 63, "fields": {"idSite": 3, "idCanal": 30, "ativo": true}}]

请注意,在字段中只有 3 个值,idSite、idCanal 和 ativo,我在查询中无能为力返回 nomeCanais,即使使用 canaisAssoc.objects.raw 和上面的查询也不起作用,关于我如何做的任何想法解决这个? 下面是我的代码!

谢谢!

Models.py

class Canais_dados(models.Model):
  id = models.AutoField(primary_key=True)
  nomeCanais = models.TextField()
  ativo = models.BooleanField(default=True)
  def __str__(self):
    return self.nomeCanais

class Formatos_dados(models.Model):
  id = models.AutoField(primary_key=True)
  nomeFormato = models.TextField()
  ativo = models.BooleanField(default=True)
  def __str__(self):
    return self.nomeFormato    `Preformatted text`

class canaisAssoc(models.Model):
  id = models.AutoField(primary_key=True)
  idSite = models.ForeignKey(Sites_dados, on_delete=models.CASCADE, related_name='idSitesCanaisAssoc',null=False)
  idCanal = models.ForeignKey(Canais_dados, on_delete=models.CASCADE, related_name='idCanaisCanaisAssoc',null=False)
  ativo = models.BooleanField(default=True,null=True)  

class formatosAssoc(models.Model):
  id = models.AutoField(primary_key=True)
  idSite = models.ForeignKey(Sites_dados, on_delete=models.CASCADE, related_name='idSiteFormatoAssoc',null=False)
  idFormato = models.ForeignKey(Formatos_dados, on_delete=models.CASCADE, related_name='idFormatoFormatoAssoc',null=False)
  ativo = models.BooleanField(default=True,null=True)
views.py

# AJAX
def load_channel(request,site):
  
  channels = canaisAssoc.objects.select_related('idCanal').filter(idSite_id = site, ativo = True).all()
  formats = formatosAssoc.objects.select_related('idFormato').filter(idSite_id = site,ativo = True).all()
  channelName = serialize("json",channels)
  serializedChannel = json.loads(channelName)
  formatName = serialize("json",formats)
  serializedFormat = json.loads(formatName)
  return JsonResponse({'formats':serializedFormat,'channel': serializedChannel})

我尝试了 objects.raw,即使那样也没有按预期工作。

我期待 JSON 返回类似的东西:

{“频道”:[{“模型”:“campanhas.canaisassoc”,“pk”:14,“字段”:{“idSite”:3,“idCanal”:13,“ativo”:真,“nomeCanais”: “Y 运河”}},{“模型”:“campanhas.canaisassoc”,“pk”:15,“字段”:{“idSite”:3,“idCanal”:1,“ativo”:true,“nomeCanais” :“CanalXX”}},{“模型”:“campanhas.canaisassoc”,“pk”:16,“字段”:{“idSite”:3,“idCanal”:4,“ativo”:true,“nomeCanais” :“CanalXXY”}},{“模型”:“campanhas.canaisassoc”,“pk”:17,“字段”:{“idSite”:3,“idCanal”:10,“ativo”:true,“nomeCanais” :“CanalXXYZ”}},{“模型”:“campanhas.canaisassoc”,“pk”:63,“字段”:{“idSite”:3,“idCanal”:30,“ativo”:true,“nomeCanais” : "CanalXXYZ"}}]

您误解了select_related的工作原理。 它的目的是减少为相关模型获取数据的数据库请求量,而不是更改它们的字段。

考虑例子:

class ModelA(models.Model):
   a_data = ...  # example field
   ...           # other-fields

class ModelB(models.Model):
   a_object = models.ForeignKey(ModelA, ...)
   b_data = ...  # example field
   ...           # other-fields

没有select_related

b_objects = ModelB.objects.all()  # first request

for b in b_objects:
    a = b.a_object     # +1 request for each a_object.
    a_data = a.a_data  # get a_data.
    b_data = b.b_data  # get b_data.
    ...                # do something.

这里第一个请求从 ModelB 的表中获取数据。 然后,对于每个a_object ,都会向 ModelA 的表发出一个额外的请求。

使用select_related

b_objects = ModelB.objects.select_related('a_object')  # first request.

for b in b_objects:
    a = b.a_object     # no extra requests.
    a_data = a.a_data  # get a_data.
    b_data = b.b_data  # get b_data.
    ...                # do something.

这里第一个请求一次性获取 ModelB 和相关的 ModelA 的数据。 没有额外的要求。 但是您从代码中访问该数据的方式并没有改变。

有关详细信息,请参阅select_related上的文档。

反向或 m-2-m 关系的类似方法: prefetch_related


您需要的是+字段查找

b_objects = ModelB.objects.values(
    'pk',                # b's own fields
    'b_data',            # b's own fields
    'a_object__pk',      # related a_object's fields
    'a_object__a_data',  # related a_object's fields
    ...                  # other fields
)

这将返回一个字典查询集,如下所示:

<QuerySet [
{'pk': 1, 'b_data': 'b_1', 'a_object__pk': 1, 'a_object__a_data': 'a_1'},
{'pk': 2, 'b_data': 'b_2', 'a_object__pk': 2, 'a_object__a_data': 'a_2'},
...]>

然后您可以在序列化之前对其进行序列化或转换为更原始的数据类型。

类似的方法values_list返回没有键的值列表:

<QuerySet [
[1, 'b_1', 1, 'a_1'],
[2, 'b_2', 2, 'a_2'],
...]>

另一种方法是使用字段查找注释+ F 对象

b_objects = ModelB.objects.annotate(
    a_pk = F('a_object__pk'),      # add a_object's pk as 'a_pk'
    a_data = F('a_object__data'),  # add a_object's a_data as 'a_data'
)

它将额外的属性添加到具有相关a对象的相应值的b对象。

将其与values相结合,为键提供更短的名称:

b_objects = ModelB.objects.annotate(
    a_pk = F('a_object__pk'),      # add a_object's pk as 'a_pk'
    a_data = F('a_object__data'),  # add a_object's a_data as 'a_data'
).values(
    'pk',      # b's own fields
    'b_data',  # b's own fields
    'a_pk',    # annotated fields
    'a_data',  # annotated fields
    ...
)

出于安全原因,不建议使用Raw


对于大于 1-2 个端点的 API,还可以考虑使用DRF 它就是为此而制作的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM