0

我正在制作一个小词汇测验应用程序,一个单词的基本模型是这样的:

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'

我目前正在测试自己的单词模型是这样的:

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'

其中“水平”表示我学得有多好。我已经学过的一组单词有这个模型:

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'

当 WordToWorkOn 上的查询集返回的结果太少时(因为它们已经学得足够好,可以移动到 WordLearned 并从 WordToWorkOn 中删除),我想找到一个 Word 来添加它。我不知道一个好方法的部分是将其限制为尚未在 WordLearned 中的单词。

所以,一般来说,我想我想对单词的查询集执行某种 .exclude() 操作,但它需要根据 WordLearned 表中的成员资格进行排除。有没有好的方法来做到这一点?我找到了很多关于加入查询集的参考资料,但找不到一个很好的关于如何做到这一点的参考资料(可能只是不知道要搜索的正确术语)。

我不想只在每个单词上使用一个标志来表示已学习、正在使用或未学习,因为最终这将是一个多用户应用程序,我不希望每个用户都有标志。因此,我认为每组有多个表会更好。

感谢所有建议。

4

1 回答 1

8

首先,关于风格的几点说明。

无需在外键字段前加上id_. _id无论如何,Django 为这些 FK 创建的底层数据库字段都带有后缀,因此您将在db.xml 中获得类似的内容id_word_id。如果您只将字段称为“单词”、“学生”等,它会使您的代码更加清晰。

此外,无需id在每个模型中指定自动字段。它们是自动创建的,只有在需要调用它们时才应指定它们。同样,无需db_table在您的 Meta 中指定,因为这也是自动完成的。

最后,无需调用__unicode__unicode 方法中的字段。字符串插值将自动执行此操作,并且再次将其省略将使您的代码更易于阅读。(如果你真的想明确地这样做,至少使用unicode(self.word)表格。)

无论如何,关于你的实际问题。您不能像这样“加入”查询集 - 进行跨模型查询的正常方法是从一个模型到另一个模型的外键。你可以这样做:

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

它在后台将执行子查询以获取当前用户的所有 WordLearned 对象,并将它们从返回的单词列表中排除。

但是,特别是考虑到您未来对多用户应用程序的需求,我认为您应该重组您的表格。您需要的是 Word 和 Student 之间的多对多关系,其中包含一个捕获特定 Student 的 Word 状态的中间表。这样你就可以摆脱 WordToWorkOn 和 WordLearned 表,它们基本上是重复的。

就像是:

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()

现在,您可以获得要为特定学生学习的所有单词:

words_to_learn = Word.objects.filter(studentword__student=student, studentword__learned=False)
于 2009-10-28T15:52:00.390 回答