2009-08-31 7 views
5

Diciamo che ho due modelli che cercano in questo modo:Come recuperare i primi due prodotti per ogni tipo di prodotto?

 
class ProductType(models.Model): 
    product_type = models.CharField(max_length=100) 

class Product(models.Model): 
    name = models.CharField(max_length=200) 
    slug = models.SlugField() 

    product_type = models.ForeignKey(ProductType) 

    score = models.PositiveIntegerField(default=0) 

ora voglio andare a prendere i primi due prodotti (i due con punteggio più alto) da ogni ProductType. Quindi se ho telefoni, computer, TV come ProductTypes voglio i due migliori telefoni, computer, TV.

Siccome non so nemmeno come farlo in MySQL, ho provato a cercare la soluzione MySQL ma quelli che trovo sono estremamente complessi e questo non mi sembra una cosa estremamente complessa da fare.

Sono propenso a creare un proprio modello per i prodotti migliori e ho un cronjob per risolvere questo problema, ma mi piacerebbe vedere se c'è una soluzione più semplice a questo.

risposta

4

Beh, si potrebbe fare un metodo all'interno della classe ProductType che restituisce i primi due risultati per i suoi prodotti:

class ProductType(models.Model): 
    product_type = models.CharField(max_length=100) 

    def TopTwoProducts(self): 
     return self.product_set.order_by('-score')[0:2] 

Poi si sarebbe solo fare qualcosa di simile:

for type in ProductType.objects.all(): 
    type.TopTwoProducts() 
+0

Soluzione intelligente, mi piace! Grazie. – rinti

+0

non capisco ... perché usi il ciclo? – IProblemFactory

+1

Si utilizza solo il ciclo for quando arriva il momento di accedere ai primi due prodotti (come elencarli in un modello o qualsiasi altra cosa). – Adam

4

mentre Adamo di la soluzione è corretta, un modo più django-ish sarebbe quello di usare un manager.

Vedere Managers versus class methods sul blog di James Bennett

Tra gli altri vantaggi:

  • un manager porta tutto il codice specifico per interrogazione, evitando di ingombrare la classe del modello
  • la stessa classe di manager può essere condivisa tra più classi
  • il gestore può essere utilizzato direttamente su una classe del modello o tramite una relazione uno-a-molti o m2m

Così, per la domanda di cui sopra:

from django.db import models 
from django.db.models.manager import Manager 

class ProductScoreManager(Manager): 

    use_for_related_field = True 

    def top_score(self, limit=2): 
     return self.get_query_set().order_by('-score')[:limit] 

Quindi aggiungere questa classe dirigente come gestore predefinito per prodotto:

class Product(models.Model): 
    ... 
    objects = ProductScoreManager() 
    ... 

Ora, grazie alla oggetti imperativi il manager di default, e use_for_related_field consentendone l'uso in relazione alle query, il metodo top_score può essere utilizzato in qualsiasi modello correlato ai prodotti.

myproducttype = ProductType.objects.get(...) 
myproducttype.products.top_score() # return top 2 products 

Questo permette una sintassi più consistente: i relativi prodotti è sempre accessibili tramite prodotti, top_score agiscono come filtro. Inoltre, la classe ProductType non è più confusa con la logica di query del prodotto.

+0

Grazie, guarderò a questo domani! – rinti

Problemi correlati