Question

Je fais une petite application de vocabulaire-quiz, et le modèle de base d'un mot est le suivant:

class Word(models.Model):
    id = models.AutoField(primary_key=True)
    word = models.CharField(max_length=80)
    id_image = models.ForeignKey(Image)
    def __unicode__(self):
        return self.word
    class Meta:
        db_table = u'word'

Le modèle de mots sur lequel je m’interroge actuellement est le suivant:

class WordToWorkOn(models.Model):
    id = models.AutoField(primary_key=True)
    id_student = models.ForeignKey(Student)
    id_word = models.ForeignKey(Word)
    level = models.IntegerField()
    def __unicode__(self):
        return u'%s %s' % (self.id_word.__unicode__(), self.id_student.__unicode__() )
    class Meta:
        db_table = u'word_to_work_on'

Où " niveau " indique à quel point je l'ai appris. L'ensemble de mots que j'ai déjà appris a ce modèle:

class WordLearned(models.Model):
    id = models.AutoField(primary_key=True)
    id_word = models.ForeignKey(Word, related_name='word_to_learn')
    id_student = models.ForeignKey(Student, related_name='student_learning_word')
    def __unicode__(self):
        return u'%s %s' % (self.id_word.__unicode__(), self.id_student.__unicode__() )
    class Meta:
        db_table = u'word_learned'

Quand un ensemble de requêtes sur WordToWorkOn revient avec trop peu de résultats (car ils ont été suffisamment bien appris pour être déplacés dans WordLearned et supprimés de WordToWorkOn), je souhaite trouver un mot à ajouter. Ce que je ne sais pas faire, c’est de limiter les mots qui ne sont pas déjà dans WordLearned.

Donc, en général, je pense que je veux faire un .exclude () de quelque sorte sur un ensemble de requêtes de mots, mais il doit être exclu en fonction de l'appartenance à la table WordLearned. Y at-il un bon moyen de le faire? Je trouve de nombreuses références à la jonction de requêtes, mais je ne trouve pas la bonne (comment ne pas trouver le bon terme).

Je ne veux pas simplement utiliser un drapeau sur chaque mot pour indiquer que vous avez appris, que vous y travaillez ou non, car il s'agira finalement d'une application multi-utilisateur et je ne voudrais pas avoir de drapeau pour chaque utilisateur. . C’est pourquoi j’ai pensé qu’il serait préférable de disposer de plusieurs tables pour chaque ensemble.

Tous les conseils sont appréciés.

Était-ce utile?

La solution

Tout d'abord, quelques notes sur le style.

Il n'est pas nécessaire de préfixer les champs de clé étrangère avec id _ . Le champ de base de données sous-jacent créé par Django pour ces FK est néanmoins doté du suffixe _id . Vous obtiendrez ainsi quelque chose comme id_word_id dans la base de données. Votre code sera beaucoup plus clair si vous n’appelez que les champs "mot", "étudiant", etc.

De plus, il n'est pas nécessaire de spécifier les champs automatiques id dans chaque modèle. Ils sont créés automatiquement et vous ne devez les spécifier que si vous devez les appeler autrement. De même, il n'est pas nécessaire de spécifier db_table dans votre méta, car cela se fait également automatiquement.

Enfin, nul besoin d'appeler __ unicode __ sur les champs de votre méthode unicode. L’interpolation de chaîne le fera automatiquement, et à nouveau, laisser le code beaucoup plus facile à lire. (Si vous voulez vraiment le faire explicitement, utilisez au moins la forme unicode (self.word) .)

Quoi qu'il en soit, passons à votre question actuelle. Vous ne pouvez pas «joindre» les jeux de requêtes en tant que tels - la manière habituelle de faire une requête entre modèles consiste à avoir une clé étrangère d'un modèle à l'autre. Vous pouvez faire ceci:

words_to_work_on = Word.objects.exclude(WordLearned.objects.filter(student=user))

qui sous le capot fera une sous-requête pour obtenir tous les objets WordLearned de l'utilisateur actuel et les exclure de la liste des mots renvoyés.

Cependant, et compte tenu en particulier de vos besoins futurs pour une application multi-utilisateurs, je pense que vous devriez restructurer vos tables. Ce que vous voulez, c'est une relation ManyToMany entre Word et Student, avec une table intermédiaire capturant le statut d'un Word pour un étudiant particulier. De cette façon, vous pouvez vous débarrasser des tables WordToWorkOn et WordLearned, qui sont essentiellement des doublons.

Quelque chose comme:

class Word(models.Model):
    word = models.CharField(max_length=80)
    image = models.ForeignKey(Image)
    def __unicode__(self):
        return self.word

class Student(models.Model):
     ... name, etc ...
     words = models.ManyToManyField(Word, through='StudentWord')

class StudentWord(models.Model):
    word = models.ForeignKey(Word)
    student = models.ForeignKey(Student)
    level = models.IntegerField()
    learned = models.BooleanField()

Vous pouvez maintenant obtenir tous les mots à apprendre pour un élève en particulier:

words_to_learn = Word.objects.filter(studentword__student=student, studentword__learned=False)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top