Pergunta

Estou fazendo um pouco de aplicativo de vocabulário-Quiz, e o modelo básico para uma palavra é a seguinte:

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'

O modelo de palavras em que estou me questionando é o seguinte:

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'

Onde "nível" indica como eu aprendi bem. O conjunto de palavras que já aprendi tem este modelo:

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'

Quando uma consulta no WordToworkon volta com poucos resultados (porque eles foram aprendidos o suficiente para serem transferidos para o WordLearned e excluído do WordToworkon), quero encontrar uma palavra para adicionar. A parte que não conheço uma boa maneira de fazer é limitá -la a palavras que ainda não estão no WordLearned.

Então, de um modo geral, acho que quero fazer um .Exclude () de algum tipo em uma consulta de palavras, mas precisa excluir com base na associação à tabela WordLearned. Existe uma boa maneira de fazer isso? Encontro muitas referências à união de consultas, mas não consegui encontrar uma boa sobre como fazer isso (provavelmente não sei o termo certo a ser procurado).

Não quero usar apenas um sinalizador em cada palavra para indicar aprendizado, trabalhar nisso ou não aprender, porque eventualmente esse será um aplicativo multiusuário e eu não gostaria de ter sinalizadores para todos os usuários. Por isso, pensei que várias tabelas para cada conjunto seria melhor.

Todos os conselhos são apreciados.

Foi útil?

Solução

Em primeiro lugar, algumas notas sobre estilo.

Não há necessidade de prefixar os campos de chave estrangeira com id_. O campo de banco de dados subjacente que o Django cria para aqueles FKs é sufixo _id Enfim, então você terá algo como id_word_id no db. Isso tornará seu código muito mais claro se você apenas chamar a 'palavra', 'aluno', etc.

Além disso, não há necessidade de especificar o id Autofields em cada modelo. Eles são criados automaticamente e você deve especificá -los apenas se precisar chamá -los de outra coisa. Da mesma forma, não há necessidade de especificar db_table na sua meta, pois isso também é feito automaticamente.

Finalmente, não há necessidade de ligar __unicode__ nos campos do seu método Unicode. A interpolação da string fará isso automaticamente e, novamente, deixá -lo de fora facilitará seu código. (Se você realmente quer fazer isso explicitamente, pelo menos use o unicode(self.word) Formato.)

De qualquer forma, para sua pergunta real. Você não pode 'participar' de consultas como tal - a maneira normal de fazer uma consulta de modelos cruzados é ter uma chave estrangeira de um modelo para o outro. Você poderia fazem isto:

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

que, sob o capô, fará uma subconsulta para obter todos os objetos WordLearned para o usuário atual e excluí -los da lista de palavras devolvidas.

No entanto, e especialmente tendo em mente o seu requisito futuro para um aplicativo multiusuário, acho que você deve reestruturar suas tabelas. O que você quer é uma relação de muita coisa entre palavras e aluno, com uma tabela intermediária capturando o status de uma palavra para um determinado aluno. Dessa forma, você pode se livrar das mesas do WordToworkon e do WordLearned, que são basicamente duplicadas.

Algo como:

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

Agora você pode obter todas as palavras para aprender para um determinado aluno:

words_to_learn = Word.objects.filter(studentword__student=student, studentword__learned=False)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top