运行Django项目:
- 通过命令行的方式: python manage.py runserver 。在本地浏览器 http://127.0.0.1:8000/ 来访问自己写的网站啦。
- 如果想要修改端口号,在运行的时候可以指定端口号, python manage.py runserver 9000 这样就可以通过 9000 端口来访问啦。另外,这样运行的项目只能在本机上能访问。
- 如果想要在其他电脑上也能访问本网站,那么需要指定 ip 地址为 0.0.0.0 。终端运行示例为: python manage.py runserver 0.0.0.0:8000 。pycharm运行,右上角项目配置修改,如下:
4. 通过 pycharm 运行。直接点击右上角的绿色箭头按钮即可运行。
注意:其他电脑必须和该电脑的iP在同一个局域网,也就是能ping通;且要关闭自己电脑的防火墙。除此之外,还要设置ALLOWED_HOSTS
:这里设置为本机的ip
ALLOWED_HOSTS
是为了限定请求中的host
值,以防止黑客构造包来发送请求。只有在列表中的host
才能访问。
如果设置为*,则所有网址都可以访问。
Django项目中project和app的关系:
app是django 项目的组成部分。一个app 代表项目中的一个模块,所有 URL 请求的响应都是 由 app 来处理。比如豆瓣,里面有图书,电影,音乐,同城等许许多多的模块,如果站 在 django 的角度来看,图书,电影这些模块就是 app ,图书,电影这些app 共同组成豆瓣这个 项目。因此这里要有一个概念,django 项目由许多app组成,一个app 可以被用到其他项目,django 也能拥有不同的 app 。
项目结构:
- manage.py :以后和项目交互基本上都是基于这个文件。一般都是在终端输入 python manage.py [子命令] 。可以输入 python manage.py help 看下能做什么事情,一般情况下不要随便编辑这个文件。
- settings.py :本项目的设置项,以后所有和项目相关的配置都是放在这个里面。
- urls.py :这个文件是用来配置URL路由的。比如访问 http://127.0.0.1/news/ 是访问新闻 列表页,这些东西就需要在这个文件中完成。
- wsgi.py :项目与 WSGI 协议兼容的 web 服务器入口,部署的时候需要用到的,一般情况下也是不需要修改的。
- APP下的index.thml:主要包含前端显示和处理的代码:h5(主要包含前端的显示代码,如:div块、链接、table表格等)和js(用于处理前端后端交互时,前端的一下处理,如:查询、填写页面数据、按钮触发、Ajax请求处理等)
- APP下的models.py:这个模块就比较简单、主要是用来定义项目所涉及的数据库中表名和各字段类型,限制等。
- APP下视图层view.py:这个模块是用来定义后端处理的函数:如:后端查询数据库、详情页面请求数据、新增、删除后端处理等等。
Django项目执行流程:
index.html为前端显示的页面,里面包含用户处理的操作:如查询、新增、删除等等,当用户触发页面的操作按钮时,系统会去urls.py里找路由(route),在urls.py匹配到对应的路径后,就会去view.py执行后端代码(后端的函数里的参数时前端操作时带过来的),执行完后端的操作,前端再接收,完成相应的前端处理。
详解urls.py、index.thml、models.py及view.py
一. view.py
- 视图一般都写在 app 的 views.py 中。并且视图里所有函数的第一个参数永远且必须是 request (一个 HttpRequest)对象。这个对象存储了请求过来的所有信息,包括携带的参数以及一些头部信息 等。
- 在视图中,一般是完成逻辑相关的操作。比如这个请求是添加一篇博客,那么可以通过 request来接收到这些数据,然后存储到数据库中,最后再把执行的结果返回给浏览器。视图函数的返回结果必须是 HttpResponseBase 对象或者子类的对象。
- 我们常用的HttpResponseBase对象或者子类对象有:JsonResponse 和HttpResponse,其中HttpResponse是用的最多的子类;JsonResponse继承了HttpResponse对象并进行二次封装。
1、view.py里的render方法、HttpResponse方法、JsonResponse方法
- render:可接收三个参数,一是request参数,二是待渲染的html模板文件,三是保存具体数据的字典参数。它的作用就是将数据填充进模板文件,最后把结果返回给浏览器。
- HttpResponse:它是作用是内部传入一个字符串参数,然后发给浏览器,不能渲染html。 (如果是Ajax请求,建议永远让服务器返回一个字典(return HttpResponse(json.dumps(字典)),可以修改返回的数据类型(如前面那个json.dumps就是修改返回类型),比较适合返回图片,视频,音频等二进制文件。
return HttpResponse(json.dumps(result), content_type="application/json")
#其中result是需要处理的字典键值对
return HttpResponse("请求路径:{}".format(request.path))
#也可以设置固定返回数据
- JsonResponse:是HttpResponse的子类,内部强制做了json转换,所以返回的一定是json,同时也支持了list的输出
return JsonResponse(result, safe=False)
return JsonResponse('{"result": "删除成功"}', safe=False)
三、视图层request对象:
1. Request对象简单实例
# views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello world")
# urls.py
from django.urls import re_path
from . import views
app_name = "Myapp"
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
]
因为我们本例种不需要使用数据库,所以不需要创建模型(models)。当你访问http: // 127.0.0.1:8000 / index / 你就应该能看到hello world字样。因为这里的index函数其实是没有用到request的参数的,所以在编辑器里面就是灰色的。
2. 现在我们将视图函数稍微改下,使用request变量打印出请求路径。
# views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("请求路径:{}".format(request.path))
3. Request对象方法和属性
(1)request.method:获取请求方法(e.g.GET, POST).
(2)request.GET or request.POST:获取GET or POST请求参数,字典形式。
(3)request.POST.get('name', default=None):获取POST请求参数
(4)request.GET.getlist('name', default=None): 获取GET参数列表
(5)request.META:包含当前HTTP请求的Headers头部信息, 字典形式。键值KEY 都是大写。如:request.META['REMOTE_ADDR']可获取用户远程IP地址。
(6)request.user:获取当前访问用户的所有信息。
(7)request.path:获取当前访问路径。
4. 常用Request.META属性
是一个Python字典,包含了所有本次HTTP请求的Header信息,常用属性包括: REQUEST_METHOD: 当前请求方法, GET或POST
(1)request.META.get('HTTP_USER_AGENT', 'unknown'): 用户浏览器的字符串, 比如Mozilla / 5.0(WindowsNT10.0;Win64;x64) AppleWebKit / 537.36。防止抛出错误异常。
(2)REMOTE_ADDR:客户端IP地址,比如54.489.10201 。
(3)PATH_INFO: 当前路径信息,如"/index", 等同于request.path
(4)如果想要知道META的所有属性,可以在view.py里写一个函数:
def index(request):
values = request.META.items()
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
return HttpResponse('<table>%s</table>' % '\n'.join(html))
5.完整的例子
# urls.py app级别的url
from django.urls import re_path
from . import views
app_name = "request_demo"
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
]
# views.py 这里就是系统的后端的实现
from django.shortcuts import render
def index(request):
user = request.user
user_agent = request.META.get('HTTP_USER_AGENT', 'unknown')
ip = request.META['REMOTE_ADDR']
context = {'user': user, 'user_agent': user_agent, 'ip': ip, }
return render(request, "request_demo/index.html", context)
# MyApp/index.html
{% block content %}
<h3>MyApp</h3>
<ul>
<li>User: {{ user }}</li>
<li>User_Agent: {{ user_agent }}</li>
<li>IP Address: {{ ip }}</li>
</ul>
{% endblock %}
理解:view.py里面的user,user_agent和ip都来自index.html;而index.html的这些数据是用户一旦点击该页面,系统自动获取到的。
二. index.html
- 前端界h5代码和JS前端请求处理函数等,都存放在HTML里
- 下面这段h5代码,实现删除界面
<!-- 删除模态框-->
<div class="modal fade" id="delete-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">删除</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>是否删除?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" id="delete-btn" class="btn btn-danger">删除</button>
</div>
</div>
</div>
</div>
- 下面这段JS代码是实现:点击删除模态框,实现删除功能
$("#delete-modal").on('show.bs.modal', function (event) {
var btnThis = $(event.relatedTarget); //触发事件的按钮
var currentDataId = btnThis.closest('tr').find('td').eq(0).text();//获取某一列的内容eq后面表示列数\
$("#delete-btn").on('click',function() {
$.ajax({
url: "{% url 'mysite:delete' %}"+"?usrNm="+"{{usr_Nm}}"+"&usrId="+"{{usr_Id}}",
type: "POST",
data: {'IIID': currentDataId, csrfmiddlewaretoken: '{{ csrf_token }}'},
dataType: "JSON",
success:function (data) {
$('#delete-modal').modal('hide');
toastr.success(JSON.parse(data)['result']);
oTable.draw(false);
}
})
});
});
// 关闭删除模态框时,解绑事件
$('#delete-modal').on('hide.bs.modal', function () {
$('#delete-btn').off('click');
});
三. models.py
models.py路径在:APP下,主要用于存放数据库信息,定义表名和字段名及类型,Meta是给这个类起的表名。
下面是其中一张表及字段名的定义
from django.db import models
class Bugs(models.Model):
filedagainst = models.CharField(db_column='filedAgainst', max_length=100, blank=True, null=True) # Field name made lowercase.
plannedfor = models.CharField(db_column='plannedFor', max_length=100, blank=True, null=True) # Field name made lowercase.
parentworkitemid = models.CharField(db_column='parentWorkitemId', max_length=100, blank=True, null=True) # Field name made lowercase.
workitemid = models.CharField(db_column='workItemId', primary_key=True, max_length=100) # Field name made lowercase.
summary = models.CharField(max_length=2000, blank=True, null=True)
description = models.CharField(max_length=2000, blank=True, null=True)
discover = models.CharField(max_length=100, blank=True, null=True)
resolvedby = models.CharField(db_column='resolvedBy', max_length=100, blank=True, null=True) # Field name made lowercase.
defecttype = models.CharField(db_column='defectType', max_length=100, blank=True, null=True) # Field name made lowercase.
creationdate = models.DateTimeField(db_column='creationDate', blank=True, null=True) # Field name made lowercase.
status = models.CharField(max_length=100, blank=True, null=True)
severity = models.CharField(max_length=100, blank=True, null=True)
update_time = models.DateTimeField(blank=True, null=True)
bug_file = models.CharField(max_length=300, blank=True, null=True)
class Meta:
managed = False
db_table = 'bugs'
四、urls.py:
专门用于与视图函数view.py映射的,如果来了一个请求,就会从这个文件中找到匹配的视图函数。
在一个网站,比如个人信息存放的页面:/profile;新闻列表页存放的页面路径是:/list;详情页面是:/content
这些信息都是在urls.py配置的;
1. 视图写完后,要与URL进行映射,在 urls.py 文件中有一个 urlpatterns 变量,该变量在url文件中是一个url映射列表。
2. 在用户输入了某个 url ,请求到我们的网站的时候,django 会在项目的urls.py文件中,遍历urlpatterns列表来查找对应的处理函数(视图)。当url有重复的情况则以找到的第一个为准,成功匹配后,就会执行该url后面的path方法,也就是用户可以看到的页面;如果匹配不成功则会报错。
3. Urlpatterns常用函数:path和url
1. URL嵌套:
在一个项目中,通常不会只有一个app,如果把所有的 app 的 views 中的视图都放在 urls.py 中进行映射,会让代码显得非常乱。因此 django 给我们提供了一个方法,可以在 app 内部包含自己的 url 匹配规则,而在项目的 urls.py 中再统一包含这个 app 的 urls 。使用这个技术需要借助 include 函数。
- URL分为项目URL和app的URL
- 我们一般定义的都会放在app的url里,然后把整个app的url放到项目的url中进行路由
下面是项目级别的url
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'', include('mysite.urls')),
url(r'^admin/', admin.site.urls),
]
下面是app级别的url:二级路由
from django.conf.urls import url
from django.views import static
from django.conf import settings
from . import views
app_name = 'mysite'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^add-ol-issue$', views.add_ol_issue, name='addolissue'),
url(r'^search$', views.search, name='search'),
url(r'^search2$', views.search2, name='search2'),
url(r'get_project$', views.get_project, name="get_project"),
url(r'^filldata$', views.filldata, name='filldata'),
url(r'delete$', views.delete, name='delete'),
url(r'^edit_online_page$', views.edit_online_page, name='edit_online_page'),
url(r'^tr_filldata$', views.tr_filldata, name='tr_filldata'),
url(r'^upload$', views.import_excel, name='upload'),
url(r'^static/(?P<path>.*)$', static.serve, {'document_root': settings.STATIC_ROOT}, name='static'),
url(r'^version$', views.version, name='version')
]
2.URL映射
假设后端view.py的有filldata函数,其路由流程为:
# View.py详情页面请求数据
def filldata(request):
if request.is_ajax(): # filldata
onlineproblem_id= int(request.POST['IIID'])
content = OnlineProblem.objects.filter(id=onlineproblem_id)
result = serializers.serialize("json", content)
return JsonResponse(result, safe=False)
url函数:
# urls.py详情页面请求数据(^:从字符串开头进行匹配,$:从字符串末尾进行匹配)
from django.conf.urls import url
from django.views import static
from django.conf import settings
from . import views
#从当前路径导入view,也可以用from app import views(app是自己定义的)
app_name = 'mysite'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^add-ol-issue$', views.add_ol_issue, name='addolissue'),
url(r'^search$', views.search, name='search'),
url(r'^filldata$', views.filldata, name='filldata')]
3.urls.py中urlpatterns中path函数、re_path函数和url函数
django1.x版本的from django.conf.urls import url,include,用url的路由:url()写的是正则表达式(regex)的路由
Django2.x版本的from django.urls import path, re_path, include用path和re_path路由:path()写的是非正则路由(route)
(1)django1.x中的url:
函数传递了四个参数,两个必需:regex
和view
,以及两个可选:kwargs
,和name
。也就是正则表达式和视图是两个必填参数。
from django.conf.urls import url
from django.views import static
from django.conf import settings
from . import views
app_name = 'mysite'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^add-ol-issue$', views.add_ol_issue, name='addolissue'),
url(r'^search$', views.search, name='search'),
url(r'^search2$', views.search2, name='search2'),
url(r'get_project$', views.get_project, name="get_project"),
url(r'^filldata$', views.filldata, name='filldata'),
url(r'delete$', views.delete, name='delete'),
url(r'^edit_online_page$', views.edit_online_page, name='edit_online_page'),
url(r'^tr_filldata$', views.tr_filldata, name='tr_filldata'),
url(r'^upload$', views.import_excel, name='upload'),
url(r'^static/(?P<path>.*)$', static.serve, {'document_root': settings.STATIC_ROOT}, name='static'),
url(r'^version$', views.version, name='version')
]
(2)Django2.1的path函数
path()函数 具有四个参数,两个必须参数:route
和 view
,两个可选参数:kwargs
和 name
。即路由和视图是必填参数。
path()的route参数:
例如,URLconf在处理请求https://www.example.com/myapp/时,它会尝试匹配myapp/。处理请求https://www.example.com/myapp/?page=3 时,也只会尝试匹配 myapp/。
path()的view参数:
当 Django 找到了一个匹配的准则,就会调用这个特定的视图函数,并传入一个HttpRequest对象作为第一个参数,被“捕获”的参数以关键字参数的形式传入。
# 项目的url,路径为Myproject/urls.py 项目级别的中括号之前有,
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('book/',include("book.urls")),]
# app为book的url,book/urls.py文件:以后在请求 book 相关的url
的时候都需要加一个 book 的前缀。App级别的中括号之前没有,
from django.urls import path
from . import views
urlpatterns = [
path('list/',views.book_list),
path('detail/<book_id>/',views.book_detail)]
带参数的url的入参值,是从view.py后端代码里获取的:
def peopleList(request,book_id)
第一个request是默认的,那么路径自动匹配该函数的第二个形参,匹配格式:<int:book_id>,并返回一个正整数或零值。