【问题标题】:I can't get Django to INNER JOIN properly :(我无法让 Django 正确地进行 INNER JOIN :(
【发布时间】:2021-04-17 19:53:30
【问题描述】:

尽管到处寻找类似的问题,但我仍然无法使用带有 Django ORM 的 INNER JOIN 进行查询...抱歉,如果这听起来很愚蠢,但这是我第一次使用 Django 进行项目,尤其是 ORM。

我有一个带有 Users 表(在我的例子中名为 Fellows)的 Articles 表,Articles 表的外键是作者,并引用 Fellows 表中的 user_id。

class Fellow(models.Model):
    id = models.AutoField(db_column='ID', primary_key=True)  # ID
    user_id = models.PositiveBigIntegerField(db_column='User_ID', unique=True)  # Global User ID.
    nickname = models.CharField(db_column='Name', max_length=64, db_collation='utf8mb4_general_ci')  # Display Name
    user_password = models.CharField(db_column='User_Password', max_length=256, blank=True, null=True)  # Passwd
    gold = models.IntegerField(db_column='Gold')  # Credits
    faction = models.ForeignKey('Faction', models.RESTRICT, db_column='Faction', default=1)  # ID Faction

    class Meta:
        managed = False
        db_table = 'Fellows'

    def __str__(self):
        return self.nickname # Test.

class Article(models.Model):
    id = models.AutoField(db_column='ID', primary_key=True)  # ID
    author = models.ForeignKey('Fellow', models.CASCADE, db_column='ID_User', default=1)  # Global User ID
    title = models.CharField(db_column='Title', max_length=32)  # Title
    content = models.TextField(db_column='Content')  # Content
    posted = models.DateTimeField(db_column='Posted')  # Date Posted
    source = models.CharField(db_column='Source', max_length=64, blank=True, null=True) # Source picture url of the article.

    class Meta:
        db_table = 'Articles'

我试图获取发布文章的相关作者的显示名称,但没有成功。

这是我的views.py:

from .models import Article

def index(request):
    """
        And then Vue.JS will take care of the rest.
    """
    # articles = Article.objects.order_by('-posted')[:5] # Returns everything inside Articles table but nothing inside Fellows table.
    
    # articles = Article.objects.select_related() # No Result.
    
    # Still can't get display_name in index.html with this one.
    articles = Article.objects.raw('SELECT Fellows.Name AS Display_Name, Articles.ID, Articles.Title, Articles.Content, Articles.Posted, Articles.Source FROM Articles INNER JOIN Fellows ON Fellows.User_ID = Articles.ID_User ORDER BY Articles.ID DESC LIMIT 5;')

    data = {
        'articles': articles,
    }

    return render(request, 'home/index.html', data)

原始请求仅使用 sql 解释器返回一切正常,因此有两种选择:

  1. Django 不会执行 INNER JOIN。
  2. 我不知道如何读取模板 (index.html) 中的 Display_Name。

这就是我使用 VueJS 检索数据的方式(即使使用原始查询我也无法获得 display_name,它是空的)。

<script>
    const store = new Vuex.Store({
        state: {
            articles: [
                {% for article in articles %}
                {
                    title: '{{ article.title }}',
                    content: '{{ article.content | linebreaksbr }}',
                    source: "{% static 'home/img/' %}" + '{{article.source}}',
                    display_name: '{{article.display_name}}', // Maybe this is not how to retrieve the display_name?
                },
                {% endfor %}
            ],
        },
    });

    // Components.
    ArticleList = Vue.component('article-list', {
        data: function () { return { articles: store.state.articles } },
        template: '#article-list-template',
    });

    ArticleItem = Vue.component('article-item', {
        delimiters: ['[[', ']]'],
        props: ['id', 'title', 'content', 'source', 'display_name'],
        template: '#article-item-template',
    });
...
</script>

如果有人可以帮助我,我将不胜感激! TT

【问题讨论】:

  • 模板中的 Article.objects.select_related('author').all(){{ article.author.nickname }} 应该可以工作。您必须引用字段名称,而不是数据库列名称。
  • 谢谢您的回复,我尝试了您建议的方法,但是它返回一个空列表。我已经使用具有外键的其他模型对另一个应用程序进行了测试,但这次使用了一个简单的模板(没有 vuejs),并且它按预期工作。这次我将尝试使用具有相同表格的虚拟应用程序来找出问题所在! x_x
  • 请在代码问题中给出minimal reproducible example--cut & paste & runnable code,包括最小的代表性示例输入作为代码;期望和实际输出(包括逐字错误消息);标签和版本;明确的规范和解释。给出您可以给出的最少代码,即您显示的代码可以通过您显示的代码扩展为不正常。 (调试基础。)对于包含 DBMS 和 DDL(包括约束和索引)和输入为格式化为表的代码的 SQL。 How to Ask 停止尝试编写您的总体目标并从给定的代码中解释您的期望以及原因。

标签: django vue.js inner-join


【解决方案1】:

问题解决了,

我必须更改外键约束 Articles.ID_User 现在导致 Fellows.ID。

之前的约束导致 Fellows.User_ID。

终于可以用了:

articles = Article.objects.select_related('author').order_by('-posted')[:5]

而且确实是由 article.author 在前面访问它,就这么简单。

然而,我仍然不明白为什么在引用 Fellows.User_ID 时使用 INNER JOIN 的原始 sql 查询(使用 mysql 解释器)工作得很好,而在 ORM 中显然不是这种情况。

虽然它正在工作,但我的 sql 关系可能是错误的或不理想的,因此我仍然愿意接受建议!

【讨论】:

  • 约束不需要保持、声明或知道在 SQL 中查询。 (但如果它们成立,那么某些表达式返回的结果与您本来可以使用的其他表达式相同,否则不会。) ORM 使用 FK 让您编写映射到 SQL 的某些 OO 代码;它可能会生成仅在 FK 持有时才正确的查询,但它不需要。 (或者这可能需要较少的处理,但 DBMS 使用约束来最小化 SQL 代码的计算。)练习:了解 ORM 声明创建哪些表并将查询 OO 代码与不依赖约束的最简单等效 SQL 进行比较。
  • 查询不需要约束的原因是,在关系模型中,每个查询表达式及其表值都表示一个关系(船)/关联和满足它的行;查询从基表关系(船舶)/关联和行构建关系(船舶)/关联及其行。由于对关系模型和 ER 模型的误解,FK 普遍被错误地称为“关系”;它们和其他约束是 DBMS 用来禁止无效更新(和优化)的始终正确的语句。 (ORM 是不必要的和限制性的,只是提供了对模糊数据库的面向指针的访问。)
  • 感谢您的回复和解释!这是大量信息,本周我将花时间深入了解它的工作原理并避免将来出现这种情况,祝你有美好的一天!! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-16
  • 1970-01-01
  • 2021-06-18
  • 1970-01-01
  • 2014-03-13
相关资源
最近更新 更多