文章目录
1. 书籍展示和书籍添加_编辑_删除
1.1 代码编写流程
1. 在项目中创建app(这里面的数据库引用的其他app,所以要执行一遍数据库迁移指令)
python manage.py startapp booksys
2. 创建好的应用要和项目关联起来
在setting.py中INSTALL_APPS中添加booksys
3. 在url.py中配置url路径
from booksys import views as book_view
url(r'^books/',book_view.books)
4. 在booksys下的views中写视图函数
def books(request):
return render(request,'books.html')
5. 在template下创建books.html
6. 要用到bootstrap,就要涉及到静态文件的引入,在settings.py中进行设置
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'statics')
]
7. 在根下创建一个statics文件夹,在文件夹下创建book文件夹,里面存放自定义文件
如css、js、img,在创建一个plugins文件夹用来放bootstrap、jquery,然后在books.html
中引用加载静态文件
8. 开始在books.html表中写样式,表格里面的内容要用循环
<tr>
<td></td>
<tr>
9. 展示数据,在views中导入models,从数据库中读取数据,然后通过模板渲染进行返回给用户,
然后在books.html中写jinjia模板,进行模板渲染
10 展示书籍已完成,然后就是添加书籍,添加url 到对应的view视图,然后写数据库语句,在template
下创建一个add_book.html
11. 因为书籍展示和书籍添加有的是一样的,所以写一个模板base.html
1.2 项目主目录代码django_orm
init.py
import pymysql
pymysql.install_as_MySQLdb()
settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'booksys',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR , 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'orm01',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER':'root',
'PASSWORD':'',
}
}
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR,"statics")
]
urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
from booksys import views as book_view
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^query/', views.query),
url(r'^books/',book_view.books),
url(r'^add_book',book_view.add_book),
url(r'^edit_book/(\d+)',book_view.edit_book), # 提交修改请求,http://127.0.0.1:8000/edit_book/2
url(r'^del_book/(\d+)',book_view.del_book)
]
1.3 图书系统应用booksys
apps.py
from django.apps import AppConfig
class BooksysConfig(AppConfig):
name = 'booksys'
models.py
from django.db import models
# Create your models here.
from django.db import models
# Create your models here.
class Book(models.Model):
# 如果没有指定主键字段,默认orm会给这个表添加一个名称为id的主键自增字段
# 如果指定了,以指定的为准,那么orm不在创建那个id字段了
# nid = models.AutoField(primary_key=True) # int primary_key auto_increment
title = models.CharField(max_length=32) # varchar 书籍名称
# price = models.FloatField()#
price = models.DecimalField(max_digits=5,decimal_places=2) # 999.99
pub_date = models.DateField() # data 出版日期
publish = models.CharField(max_length=32) # 出版社名称
# xx = models.CharField(max_length=18,null=True,blank=True) # null=True,blank=True允许该字段数据为空
xx = models.CharField(max_length=18,default="xxx") #null=True,blank=True允许该字段数据为空
view.py
from django.shortcuts import render,HttpResponse,redirect
# 不同的应用创建不同的表
from booksys import models
# Create your views here.
def books(request):
book_list = models.Book.objects.all()
return render(request,'books.html',{'book_list':book_list})
def add_book(request):
if request.method == 'GET':
return render(request,'add_book.html')
else:
# request.POST是一个querydict类型,提供一个dict方法,把querydict转换成普通类型字典类型数据
data = request.POST.dict()
print(data)
# print(request.POST)
# title = request.POST.get('title')
# price = request.POST.get('price')
# pub_date = request.POST.get('pub_date')
# publish = request.POST.get('publish')
# print(title,title,pub_date,publish)
# 关键字传参可以通过**打散的形式来传入
ret = models.Book.objects.create(
**data
# title = title,
# price = price,
# pub_date = pub_date,
# publish = publish,
)
return redirect('/books/')
# return HttpResponse('ok')
def edit_book(request,book_id):
if request.method == 'GET':
old_obj = models.Book.objects.get(id=book_id)
return render(request,'edit_book.html',{'old_obj':old_obj})
else:
date = request.POST.dict()
models.Book.objects.filter(id=book_id).update(
**date
)
return redirect('/books/')
def del_book(request,book_id):
models.Book.objects.get(id=book_id).delete()
return redirect('/books/')
1.4 静态文件static
book目录下放的是css、img、js各种样式
plugins是引用的bootstrap文件
1.5 前端渲染模板template
add_book.html
{% extends 'base.html' %}
{% block content_title %}
<h1>添加书籍</h1>
{% endblock %}
{% block content %}
{# 如果action中没有写路径,就往获取当前页面下进行提交 #}
<form action="" method="post">
{# 写csrf_token可以通过后台的认证 #}
{# {% csrf_token %}#}
<div class="form-group">
<label for="title">价格</label>
<input type="text" class="form-control" id="title" placeholder="书籍名称" name="title">
</div>
<div class="form-group">
<label for="price">价格</label>
<input type="number" class="form-control" id="price" placeholder="价格" name="price">
</div>
<div class="form-group">
<label for="pub_date">出版日期</label>
<input type="date" class="form-control" id="pub_date" placeholder="出版日期" name="pub_date">
</div>
<div class="form-group">
<label for="publish">出版社</label>
<input type="text" class="form-control" id="publish" placeholder="出版社" name="publish">
</div>
{# button默认type属性就是submit,可以触发form表单。如果只想要给普通的按钮,那么type属性就写成button,不能提交form表单数据#}
{#<button type="button" class="btn btn-default">Submit</button>#}
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock %}
base.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
<div class="container">
{% block content_title %}
<h1 > 模板书籍 </h1>
{% endblock %}
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% block content %}
模板内容
{% endblock %}
</div>
</div>
</div>
</body>
<script src="{% static 'plugins/jquery.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</html>
books.html
{% extends 'base.html' %}
{% block content_title %}
<h1>查看书籍</h1>
{% endblock %}
{% block content %}
<a href="/add_book" class="btn btn-primary">添加书籍</a>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>编号</th>
<th>书籍名称</th>
<th>价格</th>
<th>出版日期</th>
<th>出版社</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for book in book_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book.title }}</td>
<td>{{ book.price }}</td>
<td>{{ book.pub_date | date:'Y-m-d' }}</td>
<td>{{ book.publish }}</td>
<td>
<a href="/edit_book/{{ book.id }}" class="btn btn-warning">编辑</a>
<a href="/del_book/{{ book.id }}" class="btn btn-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
edit_book.html
{% extends 'base.html' %}
{% block content_title %}
<h1>编辑书籍</h1>
{% endblock %}
{% block content %}
{# 如果action中没有写路径,就往获取当前页面下进行提交 #}
<form action="" method="post">
{# 写csrf_token可以通过后台的认证 #}
{# {% csrf_token %}#}
<div class="form-group">
<label for="title">价格</label>
<input type="text" value="{{ old_obj.title }}" class="form-control" id="title" placeholder="书籍名称" name="title">
</div>
<div class="form-group">
<label for="price">价格</label>
<input type="number" value="{{ old_obj.price }}" class="form-control" id="price" placeholder="价格" name="price">
</div>
<div class="form-group">
<label for="pub_date">出版日期</label>
<input type="date" value="{{ old_obj.pub_date | date:"Y-m-d" }}" class="form-control" id="pub_date" placeholder="出版日期" name="pub_date">
</div>
<div class="form-group">
<label for="publish">出版社</label>
<input type="text" value="{{ old_obj.publish }}" class="form-control" id="publish" placeholder="出版社" name="publish">
</div>
{# button默认type属性就是submit,可以触发form表单。如果只想要给普通的按钮,那么type属性就写成button,不能提交form表单数据#}
{#<button type="button" class="btn btn-default">Submit</button>#}
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock %}
2. 13个查询api接口
还记得表类.objects像是一个管理器,提供了增删改查的方法,Book.objects.all()获取所有的书籍,查询这里大家就掌握谁调用的下面的方法
<1> all(): 查询所有结果,结果是queryset类型
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象,结果也是queryset类型 Book.objects.filter(title='linux',price=100) #里面的多个条件用逗号分开,并且这几个条件必须都成立,是and的关系,or关系的我们后面再学,直接在这里写是搞不定or的
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,不是queryset类型,是行记录对象,返回结果有且只有一个,
如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常try。 Book.objects.get(id=1)
<4> exclude(**kwargs): 排除的意思,它包含了与所给筛选条件不匹配的对象,没有不等于的操作昂,用这个exclude,返回值是queryset类型 Book.objects.exclude(id=6),返回id不等于6的所有的对象,或者在queryset基础上调用,Book.objects.all().exclude(id=6)
<5> order_by(*field): queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型
models.Book.objects.all().order_by('price','id') #直接写price,默认是按照price升序排列,按照字段降序排列,就写个负号就行了order_by('-price'),order_by('price','id')是多条件排序,按照price进行升序,price相同的数据,按照id进行升序
<6> reverse(): queryset类型的数据来调用,对查询结果反向排序,返回值还是queryset类型
<7> count(): queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。
<8> first(): queryset类型的数据来调用,返回第一条记录 Book.objects.all()[0] = Book.objects.all().first(),得到的都是model对象,不是queryset
<9> last(): queryset类型的数据来调用,返回最后一条记录
<10> exists(): queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False
空的queryset类型数据也有布尔值True和False,但是一般不用它来判断数据库里面是不是有数据,如果有大量的数据,你用它来判断,那么就需要查询出所有的数据,效率太差了,用count或者exits
例:all_books = models.Book.objects.all().exists() #翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,就是通过limit 1,取一条来看看是不是有数据
<11> values(*field): 用的比较多,queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
model的实例化对象,而是一个可迭代的字典序列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他的查找方法,其他方法也是一样的。
<12> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<13> distinct(): values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录
举例子:
# 127.0.0.1:8000/query
from django.shortcuts import render,HttpResponse
from app01 import models
import datetime
# Create your views here.
def query(request):
# exclude排除
# 返回结果为queryset类型数据,通过objects控制器可以调用,queryset类型数据也能调用
# obj_list = models.Book.objects.exclude(id=2)
# obj_list = obj_list.filter(title='少年1')
# obj_list = obj_list.all()
# obj_list = models.Book.objects.exclude(id=2).filter(title__contains='少年').exclude(id=5)
# order_by 排序
# 返回结果为queryset类型数据,queryset类型数据可以调用这个方法
# obj_list = models.Book.objects.all().order_by('-id') #-id加个-号表示按照该字段降序排列, desc asc
# '''select * from app01_book order by id desc;'''
# obj_list = models.Book.objects.all().order_by('price', '-id') #按照价格升序排列,价格相同的按照id降序排列
# reverse()
# 翻转必须在排序数据的基础上
# 返回结果为queryset类型数据,queryset类型数据可以调用这个方法
# obj_list = models.Book.objects.all().order_by('-id').reverse()
# count
# queryset类型数据可以调用这个方法,返回值为数字
# obj_list = models.Book.objects.all().count()
# first\last
# queryset类型数据可以调用这个方法,返回值为模型类对象
# obj_list = models.Book.objects.all().first()
# obj_list = models.Book.objects.all()[0]
# obj_list = models.Book.objects.all().last()
# exists
# 判断查询结果是有数据
# queryset类型数据可以调用这个方法
# obj_list = models.Book.objects.all().exists() #判断是否有数据的效率高,只找一条记录 limit 1
# values
# 可以获取指定字段数据
# objects可以调用, queryset也能调用,返回结果还是queryset,内容为一个个字典数据
# obj_list = models.Book.objects.values('title', 'price')
# obj_list = models.Book.objects.filter(id=5).values('title', 'price')
# values_list
# 可以获取指定字段数据,返回结果还是queryset,内容为一个个元组数据
# obj_list = models.Book.objects.values_list('title', 'price')
# obj_list = models.Book.objects.filter(id=5).values_list('title', 'price')
# distinct 去重
# 一般配合values和values_list来使用
# distinct 去重的是整条记录,整条记录重复才是重复,要指定去重的字段才有意义
obj_list = models.Book.objects.values('price').distinct()
print(obj_list)
return HttpResponse('ok')
小提示: 有queryset方法大全,可以进行查看
3. 表关系设计
from django.db import models
# Create your models here.
# 作者表
class Author(models.Model):
name = models.CharField( max_length=32)
age = models.IntegerField()
# django2.x版本必须手动指定on_delete=models.CASCADE级联模式
# au = models.OneToOneField(to="AuthorDetail", to_field="id", on_delete=models.CASCADE)
# au = models.OneToOneField("AuthorDetail")
# au = models.IntegerField()
au = models.OneToOneField("AuthorDetail", db_constraint=False)
# db_constraint=False取消foreign key的强制约束效果,还可以继续使用orm的提供的属性或者方法来操作关系记录
# foreign key + unique
# 属性是OneToOneField或者ForeignKey,那么生成的对应字段是 属性名称_id
#作者详细信息表
class AuthorDetail(models.Model):
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField(max_length=64)
# 出版社表
class Publish(models.Model):
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
#书籍表
class Book(models.Model):
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
# publishs=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
publishs=models.ForeignKey("Publish")
authors = models.ManyToManyField('Author')
# class authortobook(models.Model):
# book_id = models.ForeignKey('Book')
# author_id = models.ForeignKey('Author')
4. 级联解释
举例子来说明表设计(下面的表操作都是按照下面的例子来看):
作者和作者详细信息是一对一关系(在哪个表写关联关系都可以,这里写到了作者里面)
解释:如果写在作者表这块,如果删除作者详情里的表记录并且关联了作者表,则都会删除。如果删除作者表,则不会删除作者信息表。
通俗理解,作者表抱着作者详情表的大腿,详情表的记录没了,关联作者表的内容也没了。作者表记录没了,不会影响作者详细表内容。
提示:OneToOneField生成的字段是属性名称_id
书籍表和出版社表是多对一关系(在多的那张表写关联关系,这里写到了书籍表中)
提示:ForeignKey属性生成的字段是属性名称_id,删除书不影响出版社,因为书籍表中有外键
书籍表和作者表是多对多关系(在哪个表写关联关系在都可以,这里写到了书籍表中)
解释:authors = models.ManyToManyField('Author')不会在当前表(Book)创建author字段,而是会自动创建一张新表app01_book_authors(名字组成应用名称+模型类小写+关联关系属性), 删除作者表和书籍表中的内容只会对第三表产生影响,因为自动生成的表中的foreignkey都指向book、author表,book和author不会相互影响。
app01_book_authors中有id、book_id、author_id, 而且authors这个字段还可以操控自动生成的第三张表
foreignKey强制约束效果很麻烦,比较恶劣
没有强制约束的效果的方法(删除不会影响对方,但是还要有关联的关系字段):
1. au = models.integerField()
这种不能使用orm提供的级联方法
2. au = models.OneToOneField("AuthorDetail",db_constraint=False)
db_constraint=False这个属性的作用:取消foreignkey的强制约束效果,和AuthorDetail建立的级联关系,可以继续使用orm给
我们提供的关联表查询或操作的各种方法,没有强制约束效果
使用级联方法:author.obj.au.birthday 拿到当前表的对象,然后.au级联关系,然后就可以拿到关联表的属性了。
5. 多表关系记录的添加
增加
from django.shortcuts import render,HttpResponse
from app01 import models
def query(request):
# 增
# 一对一关系的添加
# 先创建作者详细信息表记录
# ret = models.AuthorDetail.objects.create(
# birthday='2000-12-12',
# telephone='122',
# addr='惠州',
# )
#
#
# models.Author.objects.create(
# name='元涛',
# age=18,
## 第一种写法
# # au_id=ret.id, #如果用的是属性名称_id,那么值为关联记录的id值
## 第二种写法
# au=ret, #如果写属性名称来添加关系数据,那么值为关联记录的模型类对象
# )
# 一对多(publish表记录是提前加好了)
# pub_obj = models.Publish.objects.get(id=1)
# models.Book.objects.create(
# title='白洁2',
# price=10,
# publishDate='1980-07-07',
## 第一种写法
# # publishs=pub_obj, #如果写属性名称来添加关系数据,那么值为关联记录的模型类对象
## 第二种写法
# publishs_id=2, #如果用的是属性名称_id,那么值为关联记录的id值
#
# )
# 多对多
# book_obj = models.Book.objects.get(title='白夜行')
# author1 = models.Author.objects.get(id=1)
# author2 = models.Author.objects.get(id=2)
## 第一种写法
# book_obj.authors.add(author1,author2)
## 第二种写法
# book_obj.authors.add(1, 2)
# book_obj.authors.add(*[1,2])
return HttpRequest('ok')
6. 小提示和小练习
小提示:
1. pycharm默认只能给你创建一个应用,后面的只能用指令操作
2. 在Tools点击Run manage.py Task,这样就可以简单的输入命令了
startapp booksys
3. 应用和项目关联起来,在settings中添加一个应用
4. 自己的应用创建自己的表
5. 如果action什么都没有写,post请求就是忘当前路径上发
6. updata方法只能queryset类型数据调用