0

我有三个模型 LearnerLevel和直通模型LearnerLevel

模型如下所示:

class Learner(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    words = models.ManyToManyField('Word', through='LearnerWord', related_name='Learners')
    levels = models.ManyToManyField('Level', through='LearnerLevel', related_name='Learners')

    def __str__(self):
        return self.user.username
class Level(models.Model):
    name = models.CharField(max_length=100)
    selectedByUser = models.BooleanField(default=False)
    words = models.ManyToManyField('Word', through='LevelWord', related_name='levels')
    countWords = models.IntegerField(default=0)
    language = models.ForeignKey('Language', related_name='languagelevels', on_delete=models.CASCADE, null=True,
                                 blank=True)

    def __str__(self):
        return self.name

class LearnerLevel(models.Model):
    learner = models.ForeignKey('Learner', related_name='learnerlevels', on_delete=models.SET_NULL, null=True)
    level = models.ForeignKey('Level', related_name='learnerlevels', on_delete=models.SET_NULL, null=True, blank=True)
    knownWords = models.IntegerField(default=0)

    def __str__(self):
        return self.learner.user.username + ' ' + self.level.name

表格如下所示:

SELECT * FROM app_level;

id|name          |countWords|language_id|selectedByUser
1 |A1            |0         |1          |0
2 |A1 Supermarkt |0         |1          |0
3 |A1            |22        |2          |0
4 |A1 Albanisch1 |20        |4          |0
5 |A1 Albanisch2 |17        |4          |0
6 |A1 Albanisch3 |21        |4          |0
7 |A1 Albanisch4 |20        |4          |0
8 |A1 Albanisch4 |20        |4          |0
9 |A1 Albanisch5 |20        |           |0
10|A1 Albanisch7 |20        |4          |0
11|A1 Albanisch8 |20        |4          |0
12|A1 Albanisch9 |20        |4          |0
13|A1 Albanisch10|20        |4          |0
14|A1 Albanisch11|20        |4          |0
15|A1 Albanisch12|20        |4          |0

SELECT * FROM wordapp_learnerlevel;

id|knownWords|learner_id|level_id
1 |8         |1         |4
2 |16        |1         |5
3 |3         |1         |6
4 |8         |1         |1
5 |8         |2         |4

我的第一个问题是,如何使用 Django 实现以下目标?

SELECT wordapp_level.name, 
       wordapp_level.countWords, 
       wordapp_learnerlevel.knownWords 
FROM   wordapp_level 
INNER JOIN wordapp_learnerlevel 
       ON wordapp_level.id = wordapp_learnerlevel.level_id;

name         |countWords|knownWords
A1 Albanisch1|20        |8
A1 Albanisch2|17        |16
A1 Albanisch3|21        |3
A1           |0         |8
A1 Albanisch1|20        |8

我的目标是获得一个新的查询集,我可以从 django-rest-framework 的 get_queryset 函数中将其提供给模型视图。我的第二个问题是,这是好的做法吗?

我想要这样的东西:

def get_queryset(self):
    learnerStatistic = LearnerLevel.objects.select_related('level')
    return learnerStatistic

例如,学习者从 id 为 1 2 3 的级别学习。现在在 learnerlevel 中,knownWords 更改了 level_id 为 1 2 3 的位置。现在我想给用户一个统计信息。"你从level.name中学到了level.countWordslearnerlevel.knownWords "

从 Django 文档中我不清楚

========== 编辑 ==========

我试过了

str(LearnerLevel.objects.select_related('level').query)

我明白了

SELECT "wordapp_learnerlevel"."id", "wordapp_learnerlevel"."learner_id", "wordapp_learnerlevel"."level_id", "wordapp_learnerlevel"."knownWords", "wordapp_level"."id", "wordapp_level"."name", "wordapp_level"."selectedByUser", "wordapp_level"."countWords", "wordapp_level"."language_id" FROM "wordapp_learnerlevel" LEFT OUTER JOIN "wordapp_level" ON ("wordapp_learnerlevel"."level_id" = "wordapp_level"."id")'

但当

str(LearnerLevel.objects.select_related('level').values().query)

我明白了

SELECT "wordapp_learnerlevel"."id", "wordapp_learnerlevel"."learner_id", "wordapp_learnerlevel"."level_id", "wordapp_learnerlevel"."knownWords" FROM "wordapp_learnerlevel"

但我只想要learnerlevel.knownWordslevel.countWordslevel.name

如果我做

qs = LearnerLevel.objects.select_related('level').only('knownWords','level__name','level__countWords')

然后

qs.values()

<QuerySet [{'id': 1, 'learner_id': 1, 'level_id': 4, 'knownWords': 8}, {'id': 2, 'learner_id': 1, 'level_id': 5, 'knownWords': 16}, {'id': 3, 'learner_id': 1, 'level_id': 6, 'knownWords': 3}, {'id': 4, 'learner_id': 1, 'level_id': 1, 'knownWords': 8}, {'id': 5, 'learner_id': 2, 'level_id': 4, 'knownWords': 8}]>

但我希望它是

<QuerySet [{'id': 1, 'name': 'A1', 'knownWords': 8, 'countWords': xx}, .....]>

======解决方案======

我找到了解决方案

def get_queryset(self):
    currLearner = Learner.objects.get(user=self.request.user)
    return currLearner.learnerlevels.values('knownWords', 'level__name', 'level__countWords')

并且序列化器是

class LearnerLevelXXSerializer(serializers.Serializer):
    knownWords = serializers.IntegerField()
    level__name = serializers.CharField(max_length=200)
    level__countWords = serializers.IntegerField()

谢谢丹尼斯·科内尔。你的建议帮助了我

4

1 回答 1

1

关于第一个问题:您可以使用所见的查询集完全实现结果。LearnerLevel由于关系是 1:n (一个可以有多个),因此Level您从LearnerLevel, 和对象开始。select_relatedLevel

总是帮助我从纯 SQL 到 Django ORM 的一件事:使用.queryand 转换为字符串,然后您将看到 django 生成的 sql 查询(添加了 sql 格式):

./manage.py shell
>>> from wordapp.models import Level, LearnerLevel
>>> qs = LearnerLevel.objects.select_related('level')
>>> str(qs.query)
'SELECT 
"wordapp_learnerlevel"."id", 
"wordapp_learnerlevel"."learner_id", 
"wordapp_learnerlevel"."level_id", 
"wordapp_learnerlevel"."knownWords", 
"wordapp_level"."id", 
"wordapp_level"."name", 
"wordapp_level"."selectedByUser", 
"wordapp_level"."countWords" 
FROM "wordapp_learnerlevel" 
LEFT OUTER JOIN "wordapp_level" ON (
    "wordapp_learnerlevel"."level_id" = "wordapp_level"."id"
)'
>>>

现在你当然可以减少结果列(通过使用.values().only()或类似的),通常特别是当你使用其他 django-libraries(如 django-rest-framework)时,直接使用模型实例更容易,直到你必须优化表现。

关于第二个问题:这可能是一个好习惯。通常对于 REST-API,您尝试考虑资源和资源列表(DRF 在顶部添加了列表/详细信息操作)。在我看来,您的示例适合资源,因为您要返回所有用户语言的级别。

希望我能帮上忙。

于 2019-12-01T08:51:41.243 回答