簡體   English   中英

如何改進這種多對多的Django ORM查詢和模型集?

[英]How can I improve this many-to-many Django ORM query and model set?

我有一個Django查詢和一些Python代碼,我正在嘗試優化,因為1)它很丑,它不像我可以用來編寫它的一些SQL,2)因為數據的層次重組對我來說看起來很混亂。

那么,1。是否可以將其改進為單個查詢? 2.如何將我的Python代碼改進為Pythonic?

背景

這是一個照相館系統。 特定視圖正在嘗試顯示圖庫中所有照片的縮略圖。 每張照片都是靜態調整大小幾次,以避免動態調整大小,我還想檢索每個大小的URL和“大小類型”(例如縮略圖,中等,大),以便我可以Lightbox替代大小而不再訪問數據庫。

實體

我有5個相關的模型:

class Gallery(models.Model):
    Photos = models.ManyToManyField('Photo', through = 'GalleryPhoto', blank = True, null = True)

class GalleryPhoto(models.Model):
    Gallery = models.ForeignKey('Gallery')
    Photo = models.ForeignKey('Photo')
    Order = models.PositiveIntegerField(default = 1)

class Photo(models.Model):
    GUID = models.CharField(max_length = 32)

class PhotoSize(models.Model):
    Photo = models.ForeignKey('Photo')
    PhotoSizing = models.ForeignKey('PhotoSizing')
    PhotoURL = models.CharField(max_length = 1000)

class PhotoSizing(models.Model):
    SizeName = models.CharField(max_length = 20)
    Width = models.IntegerField(default = 0, null = True, blank = True)
    Height = models.IntegerField(default = 0, null = True, blank = True)
    Type = models.CharField(max_length = 10, null = True, blank = True)

所以,粗略的想法是我希望通過GalleryPhoto獲取圖庫中的所有照片,並且對於每張照片,我想獲得所有的PhotoSizes,我希望能夠通過循環訪問所有這些數據。字典。

SQL的粗略草圖可能如下所示:

Select PhotoSize.PhotoURL
From PhotoSize
Inner Join Photo On Photo.id = PhotoSize.Photo_id
Inner Join GalleryPhoto On GalleryPhoto.Photo_id = Photo.id
Inner Join Gallery On Gallery.id = GalleryPhoto.Gallery_id
Where Gallery.id = 5
Order By GalleryPhoto.Order Asc

我想將其轉換為具有如下模式的列表:

(
    photo: {
        'guid': 'abcdefg',
        'sizes': {
            'Thumbnail': 'http://mysite/image1_thumb.jpg',
            'Large': 'http://mysite/image1_full.jpg',
            more sizes...
        }
    },
    more photos...
)

我目前有以下Python代碼(它並不完全模仿上面的模式,但它會做一個例子)。

gallery_photos = [(photo.Photo_id, photo.Order) for photo in GalleryPhoto.objects.filter(Gallery = gallery)]
photo_list = list(PhotoSize.objects.select_related('Photo', 'PhotoSizing').filter(Photo__id__in=[gallery_photo[0] for gallery_photo in gallery_photos]))

photos = {}
for photo in photo_list:
    order = 1
    for gallery_photo in gallery_photos:
        if gallery_photo[0] == photo.Photo.id:
            order = gallery_photo[1] //this gets the order column value

            guid = photo.Photo.GUID
            if not guid in photos:
                photos[guid] = { 'Photo': photo.Photo, 'Thumbnail': None, 'Sizes': [], 'Order': order }

            photos[guid]['Sizes'].append(photo)

    sorted_photos = sorted(photos.values(), key=operator.itemgetter('Order'))

實際問題,第1部分

所以,我的問題首先是我是否可以更好地進行多對多查詢,這樣我就不必對gallery_photos和photo_list進行雙重查詢。

實際問題,第2部分

我看看這段代碼,我對它的外觀並不太興奮。 我當然希望有一種更好的方法可以將列名稱的分層查詢集結果分組到字典中。 在那兒?

當你有sql查詢時,使用orm很難編寫 - 你可以使用postgresql視圖。 關於mysql不確定。 在這種情況下,您將擁有:

原始SQL像:

CREATE VIEW photo_urls AS
Select
photo.id, --pseudo primary key for django mapper
Gallery.id as gallery_id, 
PhotoSize.PhotoURL as photo_url
From PhotoSize
Inner Join Photo On Photo.id = PhotoSize.Photo_id
Inner Join GalleryPhoto On GalleryPhoto.Photo_id = Photo.id
Inner Join Gallery On Gallery.id = GalleryPhoto.Gallery_id
Order By GalleryPhoto.Order Asc

Django模型如:

class PhotoUrls(models.Model):
    class Meta: 
         managed = False 
         db_table = 'photo_urls'
    gallery_id = models.IntegerField()
    photo_url = models.CharField()

ORM Queryset如:

PhotoUrls.objects.filter(gallery_id=5)

希望它會有所幫助。

Django有一些內置函數可以清理代碼的外觀。 它會產生子查詢,所以我想這取決於性能。 https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.values

gallery_photos = GalleryPhoto.objects.filter(Gallery=gallery).values('Photo_id', 'Order')
photo_queryset = PhotoSize.objects.selected_related('Photo', 'PhotoSizing').filter(
                 Photo__id__in=gallery_photos.values_list('Photo_id', flat=True))

調用list()將立即評估查詢集,如果你有大量數據,這可能會影響性能。

此外, if gallery_photo[0] == photo.Photo.id:應該有一個相當簡單的方法擺脫if gallery_photo[0] == photo.Photo.id:這似乎可以很容易地解決另一個查詢,獲取所有照片的gallery_photos。

您可以使用單個查詢檢索所有數據,並獲取數據字典列表。 然后你可以管理這個字典或創建一個新字典來形成你的最終字典...你可以在過濾和從表中選擇特定行時使用反向關系...所以:

x成為您選擇的Galery ......

GalleryPhoto.objexts.filter(Galery=x).values('Order', 'Photo__GUID', 'Photo__Photo__PhotoURL', 'Photo__Photo__PhotoSizing__SizeName', 'Photo__Photo__PhotoSizing__Width', 'Photo__Photo__PhotoSizing__Height', 'Photo__Photo__PhotoSizing__Type')

使用Photo__將創建一個inner joinPhoto表,而Photo__Photo__將創建inner joinPhotoSize (通過反向關系)和Photo__Photo__PhotoSizing__inner joinPhotoSizing ....

你得到一個詞典列表:

[{'Order':....,'GUID': ..., 'PhotoURL':....., 'SizeName':...., 'Width':...., 'Height':..., 'Type':...}, {'Order':....,'GUID': ..., 'PhotoURL':....., 'SizeName':...., 'Width':...., 'Height':..., 'Type':...},....]

您可以選擇所需的行並將所有值作為字典列表...然后您可以編寫循環函數或迭代器來遍歷此列表並創建一個新的字典組合您的數據...

暫無
暫無

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

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