2009-12-17 4 views
2

je lance un site Web d'annotation de laboratoire où les utilisateurs peuvent annoter des échantillons avec des étiquettes relatives à la maladie, le type de tissu, etc. Voici un exemple simple de models.py:Recherche d'instances multiples d'une étiquette avec Django « à » champ

from django.contrib.auth.models import User 
from django.db import models 


class Sample(models.Model): 
    name = models.CharField(max_length = 255) 
    tags=models.ManyToManyField('Tag', through = 'Annot') 

class Tag(models.Model): 
    name = models.CharField(max_length = 255) 

class Annot(models.Model): 
    tag = models.ForeignKey('Tag') 
    sample = models.ForeignKey('Sample') 
    user = models.ForeignKey(User, null = True) 
    date = models.DateField(auto_now_add = True) 

Je cherche une requête dans l'ORM de django qui retournera les balises dans lesquelles deux utilisateurs sont d'accord sur l'annotation de la même balise. Il serait utile que je puisse fournir une liste d'utilisateurs pour limiter ma requête (si quelqu'un ne croit que User1 et User2 et veut trouver les paires d'échantillons/tags sur lesquelles ils sont seuls d'accord.)

+0

Voulez-vous les balises dans lesquelles deux utilisateurs sont d'accord exactement ou AU MOINS deux utilisateurs sont d'accord? – cethegeek

+0

AU MOINS N utilisateurs – JudoWill

+0

Et je pense que vous voulez dire 'dans lequel deux utilisateurs sont d'accord sur l'annotation de même SAMPLE.', correct? – cethegeek

Répondre

1

Je pense avoir compris avoir besoin. Celui-ci m'a fait réfléchir, merci! :-)

je crois que l'équivalent requête SQL serait quelque chose comme:

select t.name, s.name, count(user_id) count_of_users 
    from yourapp_annot a, yourapp_tag t, yourapp_sample s 
where a.tag_id = t.id 
    and s.id = a.sample_id 
group by t.name, s.name 
having count_of_users > 1 

Alors que j'essaie de ne pas penser à SQL quand je viens avec navigation modèle django (il a tendance à se mettre en le chemin); quand il s'agit de requêtes d'agrégation, cela m'aide toujours à visualiser ce que serait le SQL. En django nous avons maintenant aggregations.

Voici ce que je suis venu avec:

models.Annot.objects.select_related().values(
    'tag__name','sample__name').annotate(
    count_of_users=Count('user__id')).filter(count_of_users__gt=1) 

Le jeu de résultats contiendra l'étiquette, l'échantillon et le nombre d'utilisateurs qui marqué ledit échantillon avec ladite étiquette.

casser à part pour les gens qui ne sont pas utilisés pour django agrégation:

models.Annot.objects.select_related()

  • select_related() oblige toutes les tables liées à Annot à être récupérées dans la même requête
  • Ceci est ce que me permettra de spécifier tag__name et sample__name dans les valeurs() appel

values('tag__name','sample__name')

  • values() limite les champs pour récupérer à tag.name et sample.name
  • Cela fait en sorte que mon agrégation sur le nombre de clients par groupe seulement ces champs

annotate(count_of_users=Count('user__id'))

  • annotate() ajoute une agrégation en tant que champ supplémentaire à une requête

filter(count_of_users__gt=1)

  • Et enfin je filtre sur le nombre total.

Si vous souhaitez ajouter un filtre supplémentaire sur ce que les utilisateurs doivent être pris en compte, vous devez faire ceci:

models.Annot.objects.filter(user=[... list of users...]).select_related().values(
    'tag__name','sample__name').annotate(
    count_of_users=Count('user__id')).filter(count_of_users__gt=1) 

Je pense que c'est.


Une chose ... Notez que j'ai utilisé tag__name et sample__name dans la requête ci-dessus. Mais vos modèles ne spécifient pas que les noms de balises et les noms d'échantillons sont unique.

Devraient-ils être uniques? Ajoutez un unique=True aux définitions de champ dans les modèles.

Ne devraient-ils pas être uniques? Vous devez remplacer tag__name et sample__name par tag__id et sample__id dans la requête ci-dessus.

+0

semble très bien ... avec une bonne explication, en vérifiant maintenant – JudoWill

+0

fonctionne parfaitement, couldn Je n'ai rien demandé de mieux! – JudoWill

+0

Heureux que ça a aidé. Vérifiez mon édition sur l'unicité, s'il vous plaît. – cethegeek

Questions connexes