2017-08-01 51 views
1

我有Book,Profile,Book_stat模型如下。我試圖最小化Book模型和prefetch_related方法的字段,以從Book_stat模型中獲取數據。Django - objects.values()和prefetch_related()在同一個查詢中

models.py

class Book(models.Model): 
    title = models.CharField(max_length=200) 
    image = models.FileField(upload_to="mp/", blank=True) 

    def __str__(self): 
     return self.title 

class Profile(models.Model): 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    full_name = models.CharField(max_length=150) 

    def __str__(self): 
     return self.full_name 

class Book_stat(models.Model): 
    user = models.ForeignKey(User) 
    book = models.ForeignKey(Book) 
    rating = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal('0.00')) 
    like = models.BooleanField(default=False) 

    def __str__(self): 
     return self.book.title + ' by: ' + self.user.profile.full_name 

views.py

def books(request): 
    books = books = Book.objects.prefetch_related('book_stat_set').values('id','title', 'image') 
    for book in books: 
     for book_stat in book.book_stat_set.all(): # error: 'dict' object has no attribute 'book_stat_set' 
      book.stats = book_stat 
      pprint(vars(book_stat)) 
    return HttpResponse(books, content_type= 'json') 

1)我想的json response發送到前端如下
2)如果可能,我想用book_stat_set.values('like', 'rating'),而不是book_stat_set.all(),使我查詢likerating只有

books = [ 
    { 
     id: 1, 
     title: 'some title1', 
     image: 'image1.jpg', 
     stats: { 
      like: true, 
      rating: 3.50 
     } 
    }, 
    { 
     id: 2, 
     title: 'some title2', 
     image: 'image1.jpg', 
     stats: { 
      like: true, 
      rating: 3.50 
     } 
    } 
] 
+0

你或許應該使用Django的REST的架構,這對嵌套的序列化的支持。 –

+0

是的,但這是我唯一需要的時間。 – Srinivas

回答

1

取而代之的是values方法可以使用only和手動序列化:

from django.db.models import Prefetch 
from django.forms import model_to_dict 
from django.http import JsonResponse 

def books(request): 
    prefetch = Prefetch('book_stat_set', queryset=Book_stat.objects.only('like', 'rating')) 
    qs = Book.objects.prefetch_related(prefetch).only('id','title', 'image') 
    result = [] 
    for book in qs: 
     row = model_to_dict(book, fields=['id','title', 'image']) 
     row['image'] = row['image'].url 
     stats = [] 
     for book_stat in book.book_stat_set.all(): 
      stat = model_to_dict(book_stat, fields=['like', 'rating']) 
      stat['rating'] = str(stat['rating']) # or float(stat['rating']) - depends on your purposes 
      stats.append(stat) 
     # you can calculate an average rating here 
     row['stats'] = stats 
     result.append(row) 
    return JsonResponse(result) 
+0

謝謝,它給了我無效的json響應嘗試使用json驗證器'{'標題':'測試','stats':[{'rating':十進制('3.80'),'like':True},{ 'rating':小數('3.50'),'like':True}],'image':,'id':1} {'title':'測試2',' stats':[{'rating':Decimal('3.50'),'like':False}],'image':,'id':2}'no','在'[]裏面'爲什麼是那個? – Srinivas

+0

'FieldFile'和'Decimal'字段需要額外的序列化。我在答案中更新了代碼,請檢查。 –

+0

我還加入了django的'JsonResponse' –

1

如果你需要它只有一次,你可以用手把它序列化。

books = Book.objects.prefetch_related('book_stat_set') 

books_json = [{ 
    'id': book.id, 
    'title': book.title, 
    'image': book.image.url, 
    'stats': [ 
     { 
      'like': stat.like, 'rating': str(stat.rating) 
     } for stat in book.book_stat_set.all() 
     ] 
} for book in books] 
+0

我得到'字典'對象沒有屬性'id'以及'title'和'image',所以我用book ['id']替換了'book.id',以及其他字典,然後我得到了'dict' '對象沒有任何屬性''book_stat_set'' – Srinivas

+0

你可能與什麼書不得不混淆,在Django控制檯中測試它,它的工作原理 – iklinac

+0

我真的很感謝你的努力,我收到錯誤,因爲「Book」對象不是可下載的' – Srinivas

相關問題