2009-08-31 7 views
5

Sagen wir, ich habe zwei Modelle wie folgt aussehen:Wie hole ich die beiden besten Produkte für jeden Produkttyp?

 
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) 

Jetzt möchte ich von jedem Product die ersten beiden Produkte (die beiden mit der höchsten Punktzahl) holen. Also, wenn ich Telefone haben, Computer, Fernseher als Produkttypen möchte ich die beiden besten Handys, Computer, Fernseher.

Da ich nicht einmal weiß, wie man das in MySQL macht, habe ich versucht nach der MySQL-Lösung zu suchen, aber diejenigen, die ich finde, sind extrem komplex und das fühlt sich nicht sehr komplex an.

Ich lehnte ein eigenes Modell für die Top-Produkte zu machen und haben einen Cronjob dieses Problem zu beheben, aber ich würde gerne sehen, wenn es eine einfachere Lösung dieses Problems.

Antwort

4

Nun, könnten Sie eine Methode in der Product Klasse machen, die die ersten beiden Ergebnisse für seine Produkte zurückgibt:

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

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

Dann würden Sie wie etwas zu tun:

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

intelligente Lösung, Ich mag es! Vielen Dank. – rinti

+0

ich verstehe es nicht ... warum verwenden Sie for-Schleife? – IProblemFactory

+1

Sie nur die for-Schleife verwenden, wenn es an der Zeit die ersten beiden Produkte (wie die Auflistung sie in einer Vorlage oder was auch immer) für den Zugriff kommt. – Adam

4

Während Adams Lösung ist richtig, ein django-ish Weg wäre, einen Manager zu verwenden.

See Managers versus class methods auf James Bennett Blog

Neben anderen Vorteilen:

  • ein Manager führt alle Abfrage-spezifischen Code, unter Vermeidung der Modellklasse
  • die gleiche Managerklasse Krempel kann geteilt werden unter mehreren Klassen
  • der Manager kann direkt in einer Modellklasse oder über eine Eins-zu-viele oder m2m Beziehung
0 verwendet werden

So kann die obige Frage:

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] 

Dann diese Manager-Klasse als Manager Standard hinzufügen für Produkt:

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

Nun, dank Objekte den Standard Manager überschreiben, und use_for_related_field seine Verwendung in Bezug Abfragen ermöglichen, kann das Verfahren top_score in jedem Modell im Zusammenhang mit Produkten verwendet werden.

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

Dies ermöglicht eine konsistentere Syntax: die verwandten Produkte immer über Produkte zugegriffen wird, top_score als Filter wirkt. Außerdem ist die ProductType-Klasse nicht mehr mit der Abfragelogik von Product überladen.

+0

Danke, ich schaue mir das morgen an! – rinti

Verwandte Themen