内容简介:Django模型(数据库)及Django Query常用方法
###目录:
- Django教程(一)- Django视图与网址
- Django教程(二)- Django视图与网址进阶
- Django教程(三)- Django表单Form
- Django教程(四)- Django模板及进阶
- Django模型(数据库)及Django Query常用方法
- Django教程(五)- 上传及显示
- Django实战(一)- 搭建简单的博客系统
- Django实战(二)- 创建一个课程选择系统
Django模型(数据库)及Django Query常用方法
Django 模型是与数据库相关的,与数据库相关的代码一般写在 models.py
中,Django 支持 sqlite 3, MySQL, PostgreSQL等数据库,只需要在 settings.py
中配置即可,不用更改 models.py
中的代码,丰富的API极大的方便了使用。 新建项目和应用
django-admin.py startproject learn_models # 新建一个项目 cd learn_models # 进入到该项目的文件夹 django-admin.py startapp people # 新建一个 people 应用(app)
补充:新建app也可以用 python manage.py startapp people
, 需要指出的是, django-admin.py
是安装Django后多出的一个命令,并不是运行的当前目录下的 django-admin.py
(当前目录下也没有),但创建项目会生成一个 manage.py
文件。 那project和app什么关系呢? 一个项目一般包含多个应用,一个应用也可以用在多个项目中。
添加应用 将我们新建的应用(people)添加到 settings.py 中的 INSTALLED_APPS中,也就是告诉Django有这么一个应用。
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'people', )
修改models.py 我们打开 people/models.py 文件,修改其中的代码如下:
from django.db import models class Person(models.Model): name = models.CharField(max_length=30) age = models.IntegerField()
我们新建了一个Person类,继承自models.Model, 一个人有姓名和年龄。 这里用到了两种Field,更多Field类型可以参考教程最后的链接。 创建数据表 我们来同步一下数据库(我们使用默认的数据库 SQLite3,无需配置)
先 cd 进入 manage.py 所在的那个文件夹下,输入下面的命令 # Django 1.6.x 及以下 python manage.py syncdb # Django 1.7 及以上的版本需要用以下命令 python manage.py makemigrations python manage.py migrate
我们会看到,Django生成了一系列的表,也生成了我们新建的people_person这个表,那么如何使用这个表呢?
使用 Django 提供的 QuerySet API Django提供了丰富的API, 下面演示如何使用它。
$ python manage.py shell >>> from people.models import Person >>> Person.objects.create(name="Tom", age=24) <Person: Person object> >>>
我们新建了一个用户WeizhongTu 那么如何从数据库是查询到它呢?
>>> Person.objects.get(name="Tom") <Person: Person object> >>>
我们用了一个 .objects.get() 方法查询出来符合条件的对象,但是大家注意到了没有,查询结果中显示<Person: Person object>,这里并没有显示出与Tom的相关信息,如果用户多了就无法知道查询出来的到底是谁,查询结果是否正确,我们重新修改一下 people/models.py name 和 age 等字段中不能有 __(双下划线,因为在Django QuerySet API中有特殊含义(用于关系,包含,不区分大小写,以什么开头或结尾,日期的大于小于,正则等) 也不能有 Python 中的关键字,name 是合法的,student_name 也合法,但是student__name不合法,try, class, continue 也不合法,因为它是Python的关键字( import keyword; print(keyword.kwlist) 可以打出所有的关键字)
from django.db import models class Person(models.Model): name = models.CharField(max_length=30) age = models.IntegerField() def __unicode__(self): # 在Python3中使用 def __str__(self): return self.name
按 CTRL + C 退出当前的 Python shell, 重复上面的操作,再来看看效果
新建一个对象的方法有以下几种:
1. Person.objects.create(name=name,age=age) 2. p = Person(name="Tim", age=23) p.save() 3. p = Person(name="Tony") p.age = 23 p.save() 4. Person.objects.get_or_create(name="Rose", age=23)
这种方法是防止重复很好的方法,但是速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False, 新建时返回的是True, 已经存在时返回False. 获取对象有以下方法:
Person.objects.all() Person.objects.all()[:10] 切片操作,获取10个人,不支持负索引,切片可以节约内存 Person.objects.get(name=name)
get是用来获取一个对象的,如果需要获取满足条件的一些人,就要用到filter
Person.objects.filter(name="abc") # 等于Person.objects.filter(name__exact="abc") 名称严格等于 "abc" 的人 Person.objects.filter(name__iexact="abc") # 名称为 abc 但是不区分大小写,可以找到 ABC, Abc, aBC,这些都符合条件 Person.objects.filter(name__contains="abc") # 名称中包含 "abc"的人 Person.objects.filter(name__icontains="abc") #名称中包含 "abc",且abc不区分大小写 Person.objects.filter(name__regex="^abc") # 正则表达式查询 Person.objects.filter(name__iregex="^abc") # 正则表达式不区分大小写
filter是找出满足条件的,当然也有排除符合某条件的
Person.objects.exclude(name__contains="WZ") # 排除包含 WZ 的Person对象 Person.objects.filter(name__contains="abc").exclude(age=23) # 找出名称含有abc, 但是排除年龄是23岁的
从数据库中查询出来的结果一般是一个集合,这个集合叫做 QuerySet。
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __unicode__(self): # __str__ on Python 3 return self.name class Author(models.Model): name = models.CharField(max_length=50) email = models.EmailField() def __unicode__(self): # __str__ on Python 3 return self.name class Entry(models.Model): blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __unicode__(self): # __str__ on Python 3 return self.headline
QuerySet 创建对象的方法
>>> from blog.models import Blog >>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.') >>> b.save() 总之,一共有四种方法 # 方法 1 Author.objects.create(name="Tom", email="tom@163.com") # 方法 2 twz = Author(name="Tom", email="tom@163.com") twz.save() # 方法 3 twz = Author() twz.name="Tom" twz.email="tom@163.com" twz.save() # 方法 4,首先尝试获取,不存在就创建,可以防止重复 Author.objects.get_or_create(name="Tom", email="tom@163.com") # 返回值(object, True/False)
备注:前三种方法返回的都是对应的 object,最后一种方法返回的是一个元组,(object, True/False),创建时返回 True, 已经存在时返回 False 当有一对多,多对一,或者多对多的关系的时候,先把相关的对象查询出来
>>> from blog.models import Entry >>> entry = Entry.objects.get(pk=1) >>> cheese_blog = Blog.objects.get(name="Cheddar Talk") >>> entry.blog = cheese_blog >>> entry.save()
删除符合条件的结果 和上面类似,得到满足条件的结果,然后 delete 就可以(危险操作,正式场合操作务必谨慎),比如:
Person.objects.filter(name__contains="abc").delete() # 删除 名称中包含 "abc"的人 如果写成 people = Person.objects.filter(name__contains="abc") people.delete() 效果也是一样的,Django实际只执行一条 SQL 语句。
更新某个内容 批量更新,适用于 .all() .filter() .exclude() 等后面 (危险操作,正式场合操作务必谨慎)
Person.objects.filter(name__contains="abc").update(name='xxx') # 名称中包含 "abc"的人 都改成 xxx Person.objects.all().delete() # 删除所有 Person 记录
单个 object 更新,适合于 .get(), get_or_create(), update_or_create() 等得到的 obj,和新建很类似。
aut = Author.objects.get(name="Sara") aut.name="LiMing" aut.email="Liming@163.com" aut.save() # 最后不要忘了保存!!!
QuerySet 是可迭代的,比如:
es = Entry.objects.all() for e in es: print(e.headline)
Entry.objects.all() 或者 es 就是 QuerySet 是查询所有的 Entry 条目。 注意事项: (1). 如果只是检查 Entry 中是否有对象,应该用 Entry.objects.all().exists() (2). QuerySet 支持切片 Entry.objects.all()[:10] 取出10条,可以节省内存 (3). 用 len(es) 可以得到Entry的数量,但是推荐用 Entry.objects.count()来查询数量,后者用的是SQL:SELECT COUNT(*) (4). list(es) 可以强行将 QuerySet 变成 列表 QuerySet 查询结果 排序 作者按照名称排序
Author.objects.all().order_by('name') Author.objects.all().order_by('-name') # 在 column name 前加一个负号,可以实现倒序
QuerySet 支持链式查询
Author.objects.filter(name__contains="Tom").filter(email="tom@163.com") Author.objects.filter(name__contains="Tom").exclude(email="tom@163.com") # 找出名称含有abc, 但是排除年龄是23岁的 Person.objects.filter(name__contains="abc").exclude(age=23)
QuerySet 不支持负索引
Person.objects.all()[:10] 切片操作,前10条 Person.objects.all()[-10:] 会报错!!! # 1. 使用 reverse() 解决 Person.objects.all().reverse()[:2] # 最后两条 Person.objects.all().reverse()[0] # 最后一条 # 2. 使用 order_by,在栏目名(column name)前加一个负号 Author.objects.order_by('-id')[:20] # id最大的20条
扩展:QuerySet 重复的问题,使用 .distinct() 去重复 一般的情况下,QuerySet 中不会出来重复的,重复是很罕见的,但是当跨越多张表进行检索后,结果并到一起,可以会出来重复的值
qs1 = Pathway.objects.filter(label__name='x') qs2 = Pathway.objects.filter(reaction__name='A + B >> C') qs3 = Pathway.objects.filter(inputer__name='WeizhongTu') # 合并到一起 qs = qs1 | qs2 | qs3 这个时候就有可能出现重复的 # 去重方法 qs = qs.distinct()
##实例代码操作 需求一:编写登录和注册
编写注册功能,用户名不能已经存在,如果存在需要提示重新输入 注册后可以登录,成功后可以跳转到成功登录界面
代码操作:
- register.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册页面</title> </head> <body> <form action="" method="post"> {% csrf_token %} 用户名:{{form.userName}}{{error}}<br> 密 码:{{form.password}}<br> 确认密码:{{form.repassword}}<br>{{form.non_field_errors}}<br> <input type="submit" value="注册"> <a href="{% url 'login' %}">已有账号,去登录</a> </form> </body> </html>
- login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <form action="" method="POST"> {% csrf_token %} <a href="{% url 'register' %}">没有账号?去注册</a><br> 用户名:{{form.userName}}<br> 密 码:{{form.password}}<br>{{error}}<br> <input type="submit" value="登录"> </form> </body> </html>
- loginsuc.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录成功</title> </head> <body> 登陆成功了,开不开心,意不意外。怎么还有一个网页?哈哈哈哈哈哈~<br> 用户ID:{{ request.session.id }}<br> 用户名:{{ request.session.username }} </body> </html>
- weekForm.py
# -*- coding:utf-8 -*- from django.forms import Form,widgets,fields,ValidationError class register(Form): userName = fields.CharField(max_length=10) password = fields.CharField(max_length=10,widget=widgets.PasswordInput) repassword = fields.CharField(max_length=10,widget=widgets.PasswordInput) def clean(self): userName = self.cleaned_data['userName'] password = self.cleaned_data['password'] repassword = self.cleaned_data['repassword'] if not password == repassword: myerror = '两次密码不一致,请重新输入' raise ValidationError(myerror) return self.cleaned_data class login(Form): userName = fields.CharField(max_length=10) password = fields.CharField(max_length=10,widget=widgets.PasswordInput)
- models.py
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models # Create your models here. class UserModel(models.Model): userName = models.CharField(max_length=10) password = models.CharField(max_length=10)
- views.py
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.shortcuts import render,redirect from weekForms import weekForm from models import UserModel from django.http import HttpResponse from . import models # Create your views here. def register(request): if request.method == 'GET': form = weekForm.register() return render(request,'register.html',{'form':form}) elif request.method == 'POST': form = weekForm.register(request.POST) if form.is_valid(): temp = models.UserModel.objects.filter(userName=form.cleaned_data['userName']).exists() if temp == False: userModel = UserModel() userModel.userName = form.cleaned_data['userName'] userModel.password = form.cleaned_data['password'] userModel.save() return HttpResponse('数据提交成功!您可以登录了.') else: error = '用户名已经存在!' return render(request,'register.html',{'form':form,'error':error}) else: return render(request,'register.html',{'form':form}) def login(request): if request.method == 'GET': loginform = weekForm.login() return render(request,'login.html',{'form':loginform}) elif request.method == 'POST': loginform = weekForm.login(request.POST) if loginform.is_valid(): userName = loginform.cleaned_data['userName'] password = loginform.cleaned_data['password'] user = UserModel.objects.filter(userName=userName,password=password) if user: obj = UserModel.objects.get(userName = userName) request.session['id'] = obj.id request.session['username'] = obj.userName return render(request,'loginsuc.html') #如果想直接显示可以在setting中加SESSION_SERIALIZER='django.contrib.sessions.serializers.PickleSerializer' else: error = '用户名或者密码输入有误.' return render(request,'login.html',{'form':loginform,'error':error}) else: return render(request,'login.html',{'form':loginform}) else: return redirect('https://www.zhihu.com/')
- urls.py
from django.conf.urls import url from . import views urlpatterns=[ url(r'^register/$',views.register,name='register'), url(r'^login/$',views.login,name='login') ]
效果展示:
需求二:编写宠物管理系统
- petForm.py
# -*- coding: utf-8 -*- from django.forms import Form,widgets,fields class petInfo(Form): petName = fields.CharField(max_length=10,) petId = fields.CharField(max_length=4) gender = fields.CharField(initial = '雄性', widget = widgets.Select(choices=(('雄性','雄性'),('雌性','雌性')))) year = fields.IntegerField(max_value=25,min_value=0) kind = fields.CharField(max_length=10) class PetInfo(Form): petName = fields.CharField(max_length=10,) petId = fields.CharField(max_length=4) gender = fields.CharField(initial = '雄性',widget = widgets.Select(choices=(('雄性','雄性'),('雌性','雌性')))) year = fields.IntegerField(max_value=25,min_value=0) kind = fields.CharField(max_length=10)
- html
- petlist.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>宠物管理系统</title> </head> <body> <table> <tr> <td>宠物名</td> <td>宠物编号</td> <td>宠物性别</td> <td>宠物年龄</td> <td>种类</td> </tr> {% for pet in pets %} <tr> <td>{{pet.petName}}{{disable}}</td> <td>{{pet.petId}}</td> <td>{{pet.gender}}</td> <td>{{pet.year}}</td> <td>{{pet.kind}}</td> <td><a href="">删除</a></td> <td><a href="{% url 'editpet' %}?id={{ pet.id }}">修改</a></td> </tr> {% empty %} 没有宠物信息 {% endfor %} </table> <a href="{% url 'addPet' %}">添加新宠物</a> </body> </html>
- html
- addpet.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>添加宠物信息</title> </head> <body> <form action="" method="POST"> {% csrf_token %} <input type="hidden" name="id" value="{{ id }}"> 宠物名:{{form.petName}}<br> 宠物编号:{{form.petId}}<br> 宠物性别:{{form.gender}}<br> 年 龄:{{form.year}}<br> 种类:{{form.kind}}<br> <input type="submit" value="增加宠物"> </body> </html>
- html
- editpet.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>修改宠物信息</title> </head> <body> <form action="" method="POST"> {% csrf_token %} <input type="hidden" name="id" value="{{ id }}"> 宠物名:{{pet.petName}}<br> 宠物编号:{{pet.petId}}<br> 宠物性别:{{pet.gender}}<br> 年 龄:{{pet.year}}<br> 种类:{{pet.kind}}<br> <input type="submit" value="修改"> </form> </body> </html>
- models.py
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models # Create your models here. class pet(models.Model): petName = models.CharField(max_length=10) petId = models.CharField(max_length=4) gender = models.CharField(max_length=1) year = models.IntegerField() kind = models.CharField(max_length=10)
- views.py
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.shortcuts import render from models import pet from django.http import HttpResponse from petForms import petForm from . import models from django.core.urlresolvers import reverse from django.shortcuts import redirect # Create your views here. def petlist(request): pets = models.pet.objects.all().filter(isDelete=True) return render(request,'petlist.html',{'pets':pets}) def addPet(request): if request.method == 'GET': petform = petForm.PetInfo() return render(request,'addpet.html',{'form':petform}) elif request.method == 'POST': petform = petForm.PetInfo(request.POST) if petform.is_valid(): data = petform.cleaned_data newPet = pet() newPet.petName = data['petName'] newPet.petId = data['petId'] newPet.gender = data['gender'] newPet.year = data['year'] newPet.kind = data['kind'] newPet.save() return redirect(reverse('petlist')) else: return render(request,'addpet.html',{'form':petform}) def editPet(request): if request.method == 'GET': id = request.GET.get('id',0) pets = models.pet.objects.get(pk=int(id)) petform = petForm.petInfo( initial={ 'petName':pets.petName, 'petId':pets.petId, 'gender':pets.gender, 'year':pets.year, 'kind':pets.kind, } #给需要修改的宠物添加初始属性 ) return render(request,'editpet.html',{'pet':petform,'id':id}) elif request.method == 'POST': petform = petForm.petInfo(request.POST) id = request.POST['id'] if petform.is_valid(): data = petform.cleaned_data oldPet = models.pet.objects.get(pk=int(id)) # oldPet.petName = models.Pet.objects.get(pk=int(id))['petName'] oldPet.petName = data['petName'] oldPet.petId = data['petId'] oldPet.gender = data['gender'] oldPet.year = data['year'] oldPet.kind = data['kind'] oldPet.save() return redirect(reverse('petlist')) #重定向 else: pet = models.pet.objects.get(pk=int(id)) return render(request,'editpet.html',{'pet':petform,'id':id}) def petsin(request): Pets = pet.objects.all() id = request.GET['id'] new = models.pet.objects.get(pk=int(id)) values = { 'petName':new.petName, 'petId':new.petId, 'gender':new.gender, 'year':new.year, 'kind':new.kind, } return render(request,'pet.html',{'values':values,}) def delpet(request): if request.method == 'GET': id = request.GET.get('id',0) pets = models.pet.objects.get(pk=int(id)) pets.isDelete=0 pets.save() pets = models.pet.objects.all().filter(isDelete = True) return render(request, 'petlist.html', {'pets': pets})
- urls.py
from django.conf.urls import url from . import views urlpatterns = [ url(r'addPet/$',views.addPet,name='addPet'), url(r'petlist/$',views.petlist,name='petlist'), url(r'editpet/$',views.editPet,name='editpet'), ]
效果展示:
####功能完善中,未完待续...
以上所述就是小编给大家介绍的《Django模型(数据库)及Django Query常用方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 常用的模型集成方法介绍:bagging、boosting 、stacking
- 常用的模型集成方法介绍:bagging、boosting 、stacking
- 50种常用的matplotlib可视化,再也不用担心模型背着我乱跑了
- Redis常用命令与常用配置速查手册
- Linux常用命令使用
- 常用推荐算法介绍
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。