簡體   English   中英

Django預取和select相關

[英]Django prefetch and select related

我在理解 Django ORM 中的prefetch_relatedselect_related時遇到了麻煩。 我有以下型號:

class City(models.Model):
    name = models.CharField(max_length=35)
    state = models.ForeignKey('states.State', on_delete=models.CASCADE)

class Street(models.Model):
    name = models.CharField(max_length=35)
    building = models.ForeignKey('buildings.Building', on_delete=models.CASCADE)
    city = models.ForeignKey('cities.City', on_delete=models.CASCADE)

現在我的views.py:

cities = City.objects.all()
streets = Street.objects.all()

for city in cities: 
    has_bank = streets.filter(building_id=1, city=city)
    if has_bank:
        city.has_bank = 1

    has_cinema = streets.filter(building_id=2, city=city)
    if has_cinema:
        city.has_cinema = 1

    has_church = streets.filter(building_id=3, city=city)
    if has_church:
        city.has_church = 1

但是現在每次 for 循環迭代時它都會訪問數據庫 3 次。 我正在嘗試提高時間復雜度 - 現在是3N + 2 ,其中 N 是城市數量,但我無法理解 select_related 和 prefetch_related。

你能給我一個例子嗎?我將如何改進它,這樣它就不會在 for 循環中訪問數據庫 3 次?

在您的特定情況下,我想最好使用注釋而不是預取:

from django.db.models import Count, Q

cities = City.objects
.annotate(bank_count=Count("street", filter=Q(street__building_id=1)))
.annotate(cinema_count=Count("street", filter=Q(street__building_id=2)))
.annotate(church_count=Count("street", filter=Q(street__building_id=3)))

現在您可以直接使用bank_countcinema_countchurch_count屬性:

for city in cities: 
   print(city.bank_count)
   print(city.cinema_count)
   print(city.church_count)

如果你想使用prefetch_related你需要使用Prefetch對象。 這允許您過濾預取對象:

City.objects.prefect_related(
    Prefetch("street_set", queryset=Street.objects.filter(building_id=1), to_attr='has_bank'),
    Prefetch("street_set", queryset=Street.objects.filter(building_id=2), to_attr='has_cinema'),
    Prefetch("street_set", queryset=Street.objects.filter(building_id=3), to_attr='has_church')
)

請注意to_attr參數,這可以幫助您將具有不同過濾器的同一模型的對象預取到不同的屬性。 所以你現在可以這樣做:

for city in cities: 
   print(city.has_bank)
   print(city.has_cinema)
   print(city.has_church)

選擇相關。 讓我解釋一下。 我添加了虛擬數據來解釋。

class City(models.Model):
    name = models.CharField(max_length=35)
    state = models.ForeignKey('states.State', on_delete=models.CASCADE)

class Street(models.Model):
    name = models.CharField(max_length=35)
    building = models.ForeignKey('buildings.Building', on_delete=models.CASCADE)
    city = models.ForeignKey('cities.City', on_delete=models.CASCADE)

你的城市表應該是。

id    name         state
1   Cityname1      state1  
2   Cityname2        2

你的街道表應該是。

id  name   city ..
1   st 1    1
2   stno.2  1
3   st no3  2

如果您的 orm 查詢是這樣的。

street = Street.objects.select_related('city')

此查詢將兩個表合並為單個表。這意味着所有城市 ID 外鍵都將加入每個街道 ID 以創建新表,如下所示。它將返回三個記錄,因為我們正在使用選擇相關城市,主表在這種情況下是街道,所以它將返回 3 條記錄。 在所有情況下,主表將首先在 dajngo 中返回。

 id   name   city ..  city.id  city.name  city.state
  1   st 1    1         1      Cityname1   state1
  2   stno.2  1         1      Cityname1   state1
  3   st no3  2         2      Cityname2    2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM