亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 django 中批量創建具有相關對象的對象的有效方法是什么?

在 django 中批量創建具有相關對象的對象的有效方法是什么?

哈士奇WWW 2023-10-31 14:07:44
我有以下型號:class LocationPoint(models.Model):    latitude = models.DecimalField(max_digits=16, decimal_places=12)    longitude = models.DecimalField(max_digits=16, decimal_places=12)    class Meta:        unique_together = (            ('latitude', 'longitude',),        )class GeoLogEntry(models.Model):    device = models.ForeignKey(Device, on_delete=models.PROTECT)    location_point = models.ForeignKey(LocationPoint, on_delete=models.PROTECT)    recorded_at = models.DateTimeField(db_index=True)    created_at = models.DateTimeField(auto_now_add=True, db_index=True)我有很多傳入記錄要創建(可能一次有數千個)。目前我這樣創建它們:# Simplified map function contents (removed mapping from dict as it's unrelated to the question topicpoints_models = map(lambda point: LocationPoint(latitude=latitude, longitude=longitude), points)LocationPoint.objects.bulk_create(     points_models,     ignore_conflicts=True)# Simplified map function contents (removed mapping from dict as it's unrelated to the question topicgeo_log_entries = map(            lambda log_entry: GeoLogEntry(device=device, location_point=LocationPoint.objects.get(latitude=latitude, longitude=longitude), recorded_at=log_entry.recorded_at),            log_entries        )GeoLogEntry.objects.bulk_create(geo_log_entries, ignore_conflicts=True)但我認為它不是很有效,因為它運行記錄N SELECT查詢N。有更好的方法嗎?我使用 Python 3.9、Django 3.1.2 和 PostgreSQL 12.4。
查看完整描述

2 回答

?
慕后森

TA貢獻1802條經驗 獲得超5個贊

主要問題是獲取要批量鏈接的對象。一旦我們存儲了所有這些對象,我們就可以批量獲取對象:


from django.db.models import Q


points_models = [

    LocationPoint(latitude=point.latitude, longitude=point.longitude)

    for point in points

]


LocationPoint.objects.bulk_create(

     points_models,

     ignore_conflicts=True

)


qfilter = Q(

    *[

          Q(('latitude', point.latitude), ('longitude', point.longitude))

          for point in log_entries

    ],

    _connector=Q.OR

)



data = {

    (lp.longitude, lp.latitude): lp.pk

    for lp in LocationPoint.objects.filter(qfilter)

}


geo_log_entries = [

    GeoLogEntry(

        device=entry.device,

        location_point_id=data[entry.longitude, entry.latitude],

        recorded_at=entry.recorded_at

    )

    for entry in log_entries

]


GeoLogEntry.objects.bulk_create(geo_log_entries, ignore_conflicts=True)

因此,我們批量獲取需要鏈接到的所有對象(因此使用一個查詢),創建一個映射主鍵上的經度和緯度的字典,然后設置為該點location_point_id。


然而,重要的是使用小數,或者至少是一種匹配的類型。浮點數很棘手,因為它們很容易產生舍入誤差(因此經度和緯度通常存儲為“定點”數字,例如整數大 1'000 倍或大 1'000'000 倍)。否則,您應該使用將其與通過查詢生成的數據相匹配的算法。


查看完整回答
反對 回復 2023-10-31
?
眼眸繁星

TA貢獻1873條經驗 獲得超9個贊

bulk_create(...)將以列表形式返回您創建的對象。您可以在 Python 端過濾這些對象,而不是查詢數據庫,因為它們已經被獲取。


location_points = LocationPoint.objects.bulk_create(

     points_models,

     ignore_conflicts=True

)


geo_log_entries = map(

    lambda log_entry: GeoLogEntry(

        device=device, 

        location_point=get_location_point(log_entry, location_points),      

        recorded_at=log_entry.recorded_at

    ),

    log_entries

)


GeoLogEntry.objects.bulk_create(geo_log_entries, ignore_conflicts=True)

您所需要做的就是實現get_location_point滿足您的需求


查看完整回答
反對 回復 2023-10-31
  • 2 回答
  • 0 關注
  • 207 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號