Django捡破烂随便侃
首先需要明确的一点是,我们在Django项目中需要引入css,js,前端第三方类库,从cdn引入当然很方便,但是在我们写的时候不会自动提示,这就不那么美妙了,那么应该怎么做呢?
需要在Django项目目录下面创建一个static文件夹。把所有的静态文件css,js,前端第三方类库等都放在static文件夹下。然后需要在配置文件中对static文件夹进行配置。
STATIC_URL = '/static/' # 接口前缀 跟你的静态文件夹的名字一点关系都没有,但是我们要让它与静态文件夹名字保持一致 # 静态文件配置:暴露给外界能够访问服务器静态文件夹下面所有的资源 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), # 静态文件夹的路径 ]
当外界请求访问服务器的静态资源时,会依次查找静态文件夹配置列表中所有的静态文件路径,如果找到的话立刻停止,最后都没有找到的话就返回404。
一、 下面通过一个简单的登录来阐述:
先在urls.py文件里添加路由与视图函数的对应关系:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login), # 前面是正则
]
初级版:
# 根据客户端请求方式的不同执行不同的逻辑代码
def login(request):
# 获取用户端提交的请求方式
print(request.method) # 拿到的是请求方式:全大写的字符串
if request.method == 'GET':
return render(request, 'login.html')
elif request.method == 'POST':
return HttpResponse('登录成功')
# 个人建议按照下面这种方式书写 减少代码冗余及结构混乱的问题
def login(request):
if request.method == 'POST':
return HttpResponse('OK')
return render(request,'login.html')
<div class="container"> <div class="row"> <h1 class="text-center">登录页面</h1> <!--适应各种屏幕--> <div class="col-md-6 col-md-offset-3 col-sm-6 col-sm-offset-3 col-xs-6 col-xs-offset-3"> <!--指定POST提交方式及提交到/login/--> <form action="/login/" method="post"> <p>username: <input type="text" class="form-control" name="username"></p> <p>password: <input type="password" class="form-control" name="password"></p> <input type="submit" class="btn btn-block btn-primary"> </form> </div> </div> </div>
访问时,对于隐私性强的数据,form表单一定要指定POST请求(method='POST'),否则,它默认的是GET请求提交数据,就会把你输入的敏感信息加入到请求的网址后面,这样是不安全的。
form表单触发提交数据的动作两种方式:
<input type="submit"> <button></button>
form提交数据的地址如何指定及方式:
''' action属性控制提交的地址 方式: 1.全路径 <form action="http://127.0.0.1:8000/login/"> 2.只写路径后缀 <form action="/login/"> 3.不写 (默认往当前路径提交) form表单默认是get请求 '''
POST与GET请求数据的方式:
def login(request):
if request.method == 'POST':
print(request.POST) # 可以把它当作一个大字典,里面存放了客户端POST提交的所有数据
# request.POST:<QueryDict: {'username': ['shj'], 'password': ['123']}>
print(request.POST.get('username'))
# shj,value虽然是个列表但是获取value的时候拿到却是单个元素,如果value列表里有多个元素,默认只会取最后一个
print(request.POST.getlist('username'))
# ['shj'],要想一次性获取value列表里面的所有数据,可以使用getlist()。应用场景:用户的爱好 多选框
print(request.POST['password']) # 123,这个虽然也能拿到值,但是不推荐这个写法
return HttpResponse('OK')
# 获取get请求数据的方式跟post请求完全一样!!!
print(request.GET) # <QueryDict: {}>,因为我指定了POST方式提交,所以这里收到的数据为空
return render(request, 'login.html')
以上只是一个简单的请求而已,数据是我自己写的,下面我们通过pymysql来实现从数据库实时查看数据处理数据。
基于pymysql查询实现的登录:
def login(request):
if request.method == 'POST':
# 获取用户输入的用户名和密码
username = request.POST.get('username')
password = request.POST.get('password')
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='123456',
database='test',
charset='utf8',
autocommit=True
)
cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.execute('select * from user_info where name=%s and password=%s', (username, password))
user_info = cursor.fetchall()
if user_info:
return HttpResponse('登录成功!!!')
# 查不到对应数据,就继续在登录页面登录
return render(request, 'login.html')
pycharm也有自带的连接数据库的功能:
在pycharm的右侧,点击Database即可出现连接的数据库,它支持很多数据库,比起navicat来说,减少我们切换窗口的频率
Django连接数据库:
1、首先要在配置文件settings里修改默认的配置,改成mysql,因为Django默认连的是自带的sqlite数据库。
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'test', 'HOST': '127.0.0.1', 'PORT': 3306, 'USER': 'root', 'PASSWORD': '123456' } }
2、告诉django用pymysql替换它默认mysqldb模块连接数据库
方式1:在你的项目文件夹下面的__init__.py
方式2:也可以在你的应用文件夹下面的__init__.pyimport pymysql pymysql.install_as_MySQLdb() # 告诉django用pymysql代替mysqldb连接数据库
Django自带ORM,且非常强大,比我之前写的那个牛逼到不知道哪里去了。没看过我前面博客的人可能要问了,ORM到底是什么?
ORM就是对象关系映射。它把python代码的类映射到数据库的表;把对象映射到数据库的一条记录;把对象.属性映射到一条记录的某个字段对应的值。让开发人员可以通过 对象.属性 的方式完成对数据库的操作。
Django的ORM不能用于创建数据库,但是可以创建表
提示:一个django项目就使用一个库,不要多个django项目使用一个库
既然Django有这么强大的工具,那么以后与数据库的交互,我们直接用ORM那是多么美好的一件事儿啊!
首先我们在应用的models.py文件中进行类的创建:
class User(models.Model):
# user表的主键字段名就是id,其实可以不写,会默认创建一个主键字段
id = models.AutoField(primary_key=True)
# name字段是varchar(32) CharField在定义的时候必须要加max_length参数
name = models.CharField(max_length=32)
password = models.CharField(max_length=16)
def __str__(self): # 控制打印的格式
return self.name
这还没完,不要猴急,写完代码后还得去执行两条命令,执行完了人家才会给你创建表啊。
数据库迁移(同步)命令(******)
python3 manage.py makemigrations 将你的数据库变动记录到一个小本本上(并不会帮你创建表)
python3 manage.py migrate 将你的数据库变动正在同步到数据库中
执行完上面的两条命令后,赶紧到数据库看一眼:
这个是我们的表,其他是Django自己建的,至于作用嘛以后再说。可以看到Django在帮我们建表的时候,在我们的类名前面加了一个应用的名字。一定要记得,别到时候说你建了表又查不到。
二、数据新增之注册与查询:
注意新增有两种方式:
# 操作数据库user表插入数据
# 方式1:
user_obj = models.User.objects.create(name=username,password=password)
# 方式2:
user_obj = models.User(name=username,password=password)
user_obj.save() # 对象调用save方法保存到数据库
查询所有数据
user_list = models.User.objects.all() # 获取user表所有的数据
# 只要是QuerySet对象就可以点query查看获取到当前QuerySet对象的内部sql语句
print(user_list.query)
queryset对象支持索引取值, 但是不推荐你使用 , 推荐使用自带的.first()帮你获取第一条数据
具体的注册功能如下:
def reg(request):
if request.method == 'POST':
# 获取用户输入的用户名和密码
username = request.POST.get('username')
password = request.POST.get('password')
# 插入数据
# 方式一:
# user_obj = models.User.objects.create(name=username, password=password)
# 方式二:
user_obj = models.User(name=username, password=password)
user_obj.save() # 对象调用save方法保存到数据库
print(user_obj.pk) # 获取主键字段对应的值,不管主键叫啥名字都可以拿pk取到对应的值
print(user_obj.name) # 获取用户数据的name值
print(user_obj.password) # 获取用户数据的password值
return redirect('/userlist/') # 注册完成后,给他重定向到展示页,全称是(IP+端口/userlist/)
return render(request, 'reg.html')
注册的页面:
<div class="container">
<div class="row">
<h1 class="text-center">注册页面</h1>
<div class="col-md-8 col-md-offset-2">
<form action="" method="post">
<p>username: <input type="text" name="username" class="form-control"></p>
<p>password: <input type="password" name="password" class="form-control"></p>
<input type="submit" class="btn btn-primary btn-block">
</form>
</div>
</div>
</div>
数据展示页(查询数据,交给前端渲染):
def userlist(request):
# 获取数据库数据
user_list = models.User.objects.all() # 相当于select id,name,password form user;
# print(user_list.query) # 只要结果是QuerySet对象就可以点query查看获取到当前QuerySet对象的内部sql语句
# for user_obj in user_list:
# print(user_obj.pk,user_obj.name)
return render(request, 'userlist.html', locals())
展示页的代码:
<div class="container">
<div class="row">
<h1 class="text-center">展示数据</h1>
<div class="col-md-8 col-md-offset-2">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>password</th>
<th>action</th>
</tr>
</thead>
<tbody>
{% for user_obj in user_list %}
<tr>
<td>{{ user_obj.pk }}</td>
<td>{{ user_obj.name }}</td>
<td>{{ user_obj.password }}</td>
<td>
<a href="/edit/?edit_id={{ user_obj.id }}" class="btn btn-primary">编辑</a>
<a href="/delete_user/?delete_id={{ user_obj.pk }}" class="btn btn-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
三、数据删除
models.User.objects.filter(id=1).delete() # 会将拿到的queryset对象所有的数据对象全部删除
# 但是我根据id拿到的肯定只有一条
删除是在数据展示页面做的,但是后台如何知道我要删除的是哪条数据呢?
方式1:利用input隐藏一个标签
<input type="hidden" name="edit_id" value="{{ user_obj.pk }}">
方式2:利用action提交时访问路径,偷偷塞一个
<form action="/edit/?edit_id={{ user_obj.pk }}" method="post">方式3:利用a标签href属性 ,可以指定页面跳转的路径 , href可以写全路径, 但是推荐写后缀即可。在写跳转路径的时候,我们可以偷偷塞一个它的id进去,让后台获取到并删除
<a href="/delete_user/?delete_id={{ user_obj.pk }}" class="btn btn-danger">删除</a>
之前在userlist.html展示页面中 ,我们已经在点击删除按钮时,通过href跳转,以get请求的方式塞入了一个对应删除数据的id,如此一来,只要到后台查询到就可以删除。
def delete_user(request):
# 从get请求携带的参数中获取用户想要删除的数据的id
delete_id = request.GET.get('delete_id')
models.User.objects.filter(id=delete_id).delete() # 会将queryset所有的数据对象全部删除
return redirect('/userlist/') # 删完直接跳转到数据展示页
四、数据修改
修改通过编辑页面实现。
数据查询的两种方式:
查询数据需要注意的是你获取到的到底是一个queryset还是一个数据对象
queryset对象支持索引取值 ,但是不推荐使用,推荐使用自带的.first()获取第一条数据
# 查询数据方式1
# filter当条件不存在的情况下会返回一个空的queryset对象
user_obj = models.User.objects.filter(id=edit_id).first() # 如果你是要获取数据对象first千万别忘了
# 查询数据方式2
# 用get可以直接获取到数据对象本身但是查询条件不存在的情况下直接报错
user_obj = models.User.objects.get(id=edit_id)
综合来看,还是不要用models.User.objects.get()了,否则报错了多伤脑筋!
编辑的视图函数
修改的具体过程:
userlist.html展示页面点击编辑按钮时已经塞了id,访问编辑视图函数时,GET是带着edit_id的,根据edit_id,先从数据库获取到了对应id的数据,然后把他们一起发到edit.html页面中渲染。把原来的数据先展示到编辑页面上,然后由用户决定修改用户名或者是密码。等修改完后,再点击提交按钮,就走了edit视图函数的POST请求,先获取到修改后的用户名和密码,然后根据传过来的edit_id拿到对应的数据,通过update方法对数据库的这一条记录进行更新。
def edit(request):
if request.method == 'POST':
print(request.POST)
print(request.GET)
username = request.POST.get('username')
password = request.POST.get('password')
# 获取编辑对象id的方式
# 方式1:
edit_id = request.POST.get('edit_id')
# 方式2:
edit_id = request.GET.get('edit_id')
# 更新数据库
models.User.objects.filter(id=edit_id).update(name=username, password=password)
return redirect('/userlist/')
# 获取用户想要修改的数据的id
edit_id = request.GET.get('edit_id')
# 将该数据查询出来渲染到一个编辑页面
# 查询数据方式1
user_obj = models.User.objects.filter(id=edit_id).first()
# 查询数据方式2
# 用get可以直接获取到数据对象本身但是查询条件不存在的情况下直接报错
# user_obj = models.User.objects.get(id=edit_id)
# 把user_obj传递到前端去渲染
return render(request, 'edit.html', locals())
编辑页面:
<div class="container">
<div class="row">
<h1 class="text-center">编辑数据</h1>
<div class="col-sm-6 col-md-offset-3">
<!--可以在action里访问路径塞一个id-->
<form action="/edit/?edit_id={{ user_obj.pk }}" method="post">
<!--偷偷塞一个隐藏属性,把edit_id发到edit的POST,完成修改-->
<input type="hidden" name="edit_id" value="{{ user_obj.pk }}">
<p>username: <input type="text" name="username" value="{{ user_obj.name }}" class="form-control"></p>
<p>password: <input type="text" name="password" value="{{ user_obj.password }}" class="form-control"></p>
<input type="submit" class="btn btn-warning btn-block">
</form>
</div>
</div>
</div>
需要注意的是:
queryset对象点修改、删除会作用于对象内部所有的数据对象 。 类似于批量操作。
方式1:
models.User.objects.filter(id=edit_id).update(name=username,password=password)这种方式就是不管有没有修改,所有数据都更新一次。
方式2:获取到当前数据对象
user_obj = models.User.objects.filter(id=edit_id).first()
user_obj.name = usernameuser_obj.password = password
user_obj.save()这种方式只针对用户修改过的数据进行更新
五、图书管理系统表分析
class Book(models.Model):
# id字段可以不写 默认会帮你创建一个主键id字段
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
# 一对多外键字段的建立
publish = models.ForeignKey(to='Publish') # 默认是与publish表的id字段建立关联
# 多对多外键字段建在关联的两张表的任何一张都可以,但是建议建在查询频率比较高的那张表里
author = models.ManyToManyField(to='Author') # django orm会自动帮你创建book与author表的第三张表
# 注意多对多字段不会显示到表的字段中
class Publish(models.Model):
name = models.CharField(max_length=32)
email = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
外键字段名 orm会自动在字段名后面加_id.无论你的字段名有没有_id 。
修改模型层里面的跟表相关的所有的数据,只要修改了就必须重新执行数据库迁移命令
python manage.py makemigrations 记录到小本本上,就是保存在应用下的migrations文件夹
python manage.py migrate 真正操作数据库