[英]Django prefetch and select related
我在理解 Django ORM 中的prefetch_related
和select_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_count
、 cinema_count
和church_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.