由于这些天我有空闲时间,所以我决定学习一种新语言会很不错。所以我选择python是因为它很受欢迎,并且因为我对Django感兴趣。
几个小时后,尽管所有语法相关的问题都源于一种新语言,但我还是设法进行了简单的后端逻辑设计(我的“应用”应该做什么)。现在的下一步是将我的代码介绍给Django,以便最终以某种方式使该逻辑“真实”,并在此过程中学习一些HTML,CSS。
在遵循Django的官方教程之后,我感到我学到了足够的知识来开始我的项目。
在我开始谈论Django的ORM之前,我想说的是,从我在教程中所看到和学到的东西,我完全喜欢Django的所有与Web相关的实用程序(视图,路径,模板)。至少到目前为止,它们似乎非常易于学习和使用。
现在有关ORM。
首先,我认为有必要澄清这是我生命中使用的第二个ORM。在我的其中一门课程中,我使用的第一个是Java的JPA。
从我从使用JPA中学到的知识来看,我认为ORM的主要目标之一就是尽量不要让我修改我已经编写的所有代码。这样,应用程序的开发将很容易:
我与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()
来访问它,但是我觉得这很糟糕,因为例如:
至少,我的IDE(PyCharm)无法识别这些属性。我猜他们是在运行时定义的。万一我在类中使用了许多这些属性并且弄乱了它们的名称,这可能会导致运行时错误。
将其添加到以下事实中:我可以在单独的文件中拥有我的课程(考试)和定义ForeignKey(问题)的课程。因此,我将无法轻松知道我的班级拥有哪些属性(更多错误)。
最后,我想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模型的真正含义误解了。我并没有考虑太多,我假设它们是指我实际的应用程序逻辑/后端设计模型:职责如何分配,需要满足的需求以及背后的逻辑。
我期待有人能从这种压倒性的和令人失望的感觉中启发我。感谢您阅读全文:)
答案 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)应用程序结构关系的蓝图。