簡體   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