Django ORM 数据库操作(上)
ORM介绍
映射关系:
数据库表名 ---------->类名;数据库字段 ---------->类属性;数据库表一行数据 ---------->类实例化对象;
ORM两大功能:
操作表:创建、修改、删除表;
操作数据:增删改查;
ORM利用pymysql第三方工具连接数据库,Django无法帮助我们创建数据库,只能我们创建完成后告诉它,让Django去连接;
创建表之前的准备工作
1.自己创建数据库;
2.在settings.py文件中配置mysql数据库连接,sqlite3改为mysql:
# 修改django默认sqlite3数据库为mysql
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydatabase',
'USER': 'mydatabaseuser',
'PASSWORD': 'mypassword',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
修改project中的__init__.py文件,设置Django默认连接MySQL的方式:
import pymysql
pymysql.install_as_MySQLdb()
3.创建数据库表
打开models.py文件,写入如下代码:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
models.DateField()
def __str__(self):
return self.question_text
执行命令创建
python manage.py makemigrations 创建脚本
python manage.py migrate 数据迁移
4.查看数据库的sql语句(家在settings.py文件中)
# 查看数据库执行代码
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level': 'DEBUG',
},
}
}
多对多的正反向查询
在models.py文件中的模型如下:
class Class(models.Model):
name = models.CharField(max_length=32, verbose_name='班级名称')
course = models.CharField(max_length=32, verbose_name='课程')
def __str__(self):
return self.name
class Teacher(models.Model):
name = models.CharField(max_length=32, verbose_name='姓名')
classes = models.ManyToManyField(verbose_name='所属班级', to='Class')
def __str__(self):
return self.name
题目1:查找吴老师所带班级
# 方式一:基于对象的查找
obj = models.Teacher.objects.filter(name="吴老师").first()
print(obj.classes.all())
print("吴老师带的班级",obj.classes.values("name"))
# 方式二:基于双下划线的查找
obj_cls = models.Teacher.objects.filter(name="吴老师").values("classes__name")
print("吴老师带的班级",obj_cls)
注意:查询单个的时候用.values或者value_list,不要用obj.classes.name,这样查询到的会是None,反向查询也是如此,不管是一对多,还是多对多,查询多的一方就用.all()方法。
运行结果(非此例结果):
表结构:
# 一个学生有一个班级,每个班级有好多学生,所以是多对一的关系,关联字放在多的一方
class Student(models.Model):
name = models.CharField(max_length=32, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
classes = models.ForeignKey(verbose_name='所属班级', to='Class')
def __str__(self):
return self.name
class Class(models.Model):
name = models.CharField(max_length=32, verbose_name='班级名称')
course = models.CharField(max_length=32, verbose_name='课程')
def __str__(self):
return self.name
class Teacher(models.Model):
name = models.CharField(max_length=32, verbose_name='姓名')
classes = models.ManyToManyField(verbose_name='所属班级', to='Class')
def __str__(self):
return self.name
题目2.陈凡在哪个班级
# 方式一:
print("陈凡所在班级:", models.Student.objects.filter(name="陈凡").values("classes__name")
# 方式二:
obj_class = models.Student.objects.filter(name="陈凡").first()
print("陈凡所在班级:", obj_class.classes.name)
题目3.查询陈凡所在班级的老师姓名
print("陈凡所在班级老师的姓名:", models.Student.objects.filter(name="陈凡").values("classes__teacher__name)
题目4.查询高三2班所有学生姓名
print("高三2班所有学生姓名", models.Class.object.filter(name="高三2班").values("student__name")
object_class = models.Class.object.filter(name="高三2班").first()
print("高三2班所有学生姓名", object_class.student_set.all().values("name"))
# print("高三2班所有学生姓名", object_class.student_set.name) 这样打印的结果是None
重要知识点
form表单中要用submit,如果用button切记要加上type,不然button默认的type是submit,会有影响:
<button type="button" onclick="doValidation();">提交</button>
<input type="button" onclick="doValidation();" value="提交" />
// 上面两种写法是对的,功能一样
<button onclick="doValidation();">提交</button>
// 如果写成这种,默认为submit。本来doValidation方法里有提交功能了,再加上按钮也是提交功能,会提交两次。所以使用按钮时最好指定type类型。