不了解Django的ORM-模型

时间:2019-12-28 19:56:13

标签: python django

由于这些天我有空闲时间,所以我决定学习一种新语言会很不错。所以我选择python是因为它很受欢迎,并且因为我对Django感兴趣。

几个小时后,尽管所有语法相关的问题都源于一种新语言,但我还是设法进行了简单的后端逻辑设计(我的“应用”应该做什么)。现在的下一步是将我的代码介绍给Django,以便最终以某种方式使该逻辑“真实”,并在此过程中学习一些HTML,CSS。

在遵循Django的官方教程之后,我感到我学到了足够的知识来开始我的项目。

在我开始谈论Django的ORM之前,我想说的是,从我在教程中所看到和学到的东西,我完全喜欢Django的所有与Web相关的实用程序(视图,路径,模板)。至少到目前为止,它们似乎非常易于学习和使用。

现在有关ORM。

首先,我认为有必要澄清这是我生命中使用的第二个ORM。在我的其中一门课程中,我使用的第一个是Java的JPA。

从我从使用JPA中学到的知识来看,我认为ORM的主要目标之一就是尽量不要让我修改我已经编写的所有代码。这样,应用程序的开发将很容易:

  1. st-设计后端代码(用例,应用程序的模型:类,对象,函数)。
  2. nd-将模型映射到关系模型,以便可以将其持久存储在数据库中。
  3. rd-创建视图和所有前端内容。

我与Django的ORM遇到的第一个问题是没有OneToMany关系,因此,如果在我的起始代码中我有:

    class Question:
       pass

    class Exam:
        __init__(self, questions):
            self.questions = questions     # list of questions

我不得不将其更改为:

    class Question:
       exam = models.ForeignKey('Exam', on_delete=models.CASACADE, related_name='questions', ...)

    class Exam:
       pass

也许我不是很了解Django“模型”,毕竟我只是一个新手。但是我觉得这很糟糕。如果我的类“考试”中的方法依赖于使用此类问题清单来完成工作,该怎么办。我已经看到可以使用an_exam.questions.all()来访问它,但是我觉得这很糟糕,因为例如:

  1. 至少,我的IDE(PyCharm)无法识别这些属性。我猜他们是在运行时定义的。万一我在类中使用了许多这些属性并且弄乱了它们的名称,这可能会导致运行时错误。

  2. 将其添加到以下事实中:我可以在单独的文件中拥有我的课程(考试)和定义ForeignKey(问题)的课程。因此,我将无法轻松知道我的班级拥有哪些属性(更多错误)。

  3. 最后,我想an_exam.questions.all()返回了与给定考试相关的所有问题,这些问题在数据库中已保存。那些还没有呢?

我遇到的另一个问题是我不应该覆盖__init__方法。这将使我更改类初始化的所有情况。当然,我可以解决这个问题,就像在互联网上看到的那样,定义class_method以便an_exam = Exam.new_exam();但是Django为什么要让我这样做?

合并两个问题:初始化的类如何处理通过OneToMany关系与之相关的元素列表?以“考试”为例,我不仅会诉诸创建初始化方法的阴暗想法,而且还必须创建一些额外的设置方法,这些方法利用自动生成的“问题”属性(以及其他存在的属性)正确设置属性:

class Question:
    exam = models.ForeignKey('Exam', on_delete=models.CASACADE, related_name='questions', ...)

class Exam:
    @classmethod
    def new_exam(cls, questions):
        exam = Exam()
        exam.set_questions(questions)
        return exam

    def set_questions(questions):
        for q in questions:
            q.exam = self
            q.save()
            # something like this

最后,我想说的是,我知道我是Django和python的完全新手。这就是为什么我确定我一定会误以为我所说的一切以及更多;我要这样做的目的是要有人指出我的错误。

我觉得我对Django模型的真正含义误解了。我并没有考虑太多,我假设它们是指我实际的应用程序逻辑/后端设计模型:职责如何分配,需要满足的需求以及背后的逻辑。

我期待有人能从这种压倒性的和令人失望的感觉中启发我。感谢您阅读全文:)

1 个答案:

答案 0 :(得分:1)

这是我对模型/ ORM的看法,以及它们为什么如此令人高兴:没有它们,创建和维护SQL(查询)和DDL(创建/更新数据库表)的工作量很大。使用ORM,您可以消除所有这些工作:它们定义数据库表(每个作为模型)并将PK,FK关系转换为对象关系。示例比抽象描述要好,所以这是我的一个应用程序中一个非常简单的模型的示例:

class LimitType(models.Model):
    limit = models.CharField(max_length=25, unique=True, blank=False)
    description = models.CharField(max_length=50, unique=False, blank=True)
    departments = models.ManyToManyField(Department, blank=True, related_name='departmental_limits')
    createTimestamp = models.DateTimeField(auto_now_add=True)
    updateTimestamp = models.DateTimeField(auto_now=True)
    createdById = models.ForeignKey(Users, on_delete=models.PROTECT, unique=False, null=False)
    modifiedById = models.ForeignKey(Users, on_delete=models.PROTECT, unique=False, null=False)

    def __str__(self):
        return self.limit

    class Meta:
        ordering = ["limit"]

请注意该类是Model类,而不是某些泛型类。模型应该表示数据库中的内容-他们的“工作”是将关系数据库表封装为对象。还要注意这里的思维模式,该LimitType类中的每个字段都与(可交换/可插入)数据库中的列直接相关(如果没有ORM层或类似的功能,这一壮举是不可行的)。

实例化模型后,就可以使用python的所有语法约定来收集,选择,更新和排序相关对象:

For type in LimitType.objects.all():
  type.do_something() 

此外,遍历OneToMany(和ManyToMany)关系很容易:

for type in LimitType.objects.all():
    print(type.departments.count())

这些摘录是可以在其他类或Django项目的视图中找到的那种代码。

自然,这只是冰山一角。在Django和SQLAlchemy的ORM中有许多便利的功能,值得一并学习。也许您感到困惑/沮丧是由于将模型类与其他类型的类混为一谈。将它们分开(将它们放在models.py文件中),并将其视为(1)持久性手段和(2)应用程序结构关系的蓝图。