一、简单演示
返回当前时间
url.py文件内容:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^timmer/', views.timmer),
]
views.py文件内容:
from django.shortcuts import render,HttpResponse,redirect
def timmer(request):
import time
ctime=time.time()
# return HttpResponse (ctime) #只能返回字符串
return render(request,"timmer.html", {"ctime":ctime}) #返回html,这样就能定义返回的样式
timmer.html文件内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>timmer</title>
< style >
p{
color: red;
}
</style>
</head>
<body>
{#双大括号是模板语法,里面是变量,接受views.py的参数#}
<p>当前时间:{{ ctime }}</p>
</body>
</html>
二、url控制器
1、url的分组
urls.py文件内容:
from django.conf.urls import url,include
from django.contrib import admin
from django.shortcuts import HttpResponse
from app01.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^timer/$', timer), # timer(request)
#分组
url(r'^books_achrive/(\d+)/$', book_detail), # book_detail(request,3)
url(r'^books_achrive/(\d+)/(\d+)/$', books_achrive), # books_achrive(request,2012,12)
#有名分组books_achrive后面有一个year组和一个month组
url(r'^books_achrive/(?P<year>\d+)/(?P<month>\d+)/$', books_achrive2), # books_achrive(request,year=2012,month=12)
]
views.py文件内容:
from django.shortcuts import render,HttpResponse,redirect
def book_detail(reqeust,id):
return HttpResponse(id)
def books_achrive(request,year,month):
return HttpResponse(year+":"+month)
def books_achrive2(request,month,year):
return HttpResponse(year+":"+month)
这样用户访问的路径为/books_achrive/2012/12/时,就会在URL匹配到url(r'^books_achrive/(\d+)/(\d+)/$', books_achrive),然后执行books_achrive函数
2、url的分发
在项目下的urls.py文件里面定义连接到具体的应用的路径
url(r'^app01/', include('app01.urls'), ),
然后在具体应用的urls.py文件里面定义具体的url
from django.conf.urls import url,include
from app01.views import *
urlpatterns = [
url(r'^timer/$', timer), # timer(request)
url(r'^books_achrive/(\d+)/$', book_detail), # book_detail(request,3)
url(r'^books_achrive/(?P<year>\d+)/(?P<month>\d+)/$', books_achrive2), # books_achrive(request,year=2012,month=12)
]
3、URL 的反向解析
在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
换句话讲,需要的是一个DRY 机制。除了其它有点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。
在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:
(1)在模板中:使用url 模板标签。
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
]
在模板的代码中使用下面的方法获得它们:
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
(2)在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
def redirect_to_year(request):
year = 2006.
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
(3)在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。
4、反向解析示例:登录页面
urls.py文件内容:
from django.conf.urls import url,include
from django.contrib import admin
from django.shortcuts import render,HttpResponse,redirect
from app01.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', login,name="xxx"), #定义url的别名xxx
]
views.py文件内容:
from django.shortcuts import render,HttpResponse,redirect
def login(request):
if request.method=="GET":
print(request.GET)
print(request.POST)
print(request.method)
print(request.path)
print(request.path_info)
print(request.body)
return render(request, "login.html")
else:
user=request.POST.get("user")
pwd=request.POST.get("pwd")
if 1: #用户输入的用户名和密码与数据库里面的做对比,判断是否一致
return redirect("/app01/timer/")
登录页面login.html文件内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
p{
color: red;
}
</style>
</head>
<body>
<form action="{% url 'xxx' %}" method="post">
{% csrf_token %} #解决出现Forbidden (403)错误
<p>用户名 <input type="text" name="user"></p>
<p>密码 <input type="password" name="pwd"></p>
<input type="submit">
</form>
</body>
</html>
利用反向解析的好处:访问的时候用url的别名可以避免了随着url的变化而访问路径跟着变化
三、视图层之视图函数(views)
1、HttpRequest对象的属性
(1)HttpRequest.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
(2)HttpRequest.path
一个字符串,表示请求的路径组件(不含域名)。
例如:"/music/bands/the_beatles/"
(3)HttpRequest.method
一个字符串,表示请求使用的HTTP方法。必须使用大写。
例如:"GET"、"POST"
(4)HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为None则表示使用DEFAULT_CHARSET的设置,默认为'utf-8')。
这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
接下来对属性的任何访问(例如从GET或POST中读取数据)将使用新的encoding值。
如果你知道表单数据的编码不是DEFAULT_CHARSET ,则使用它。
(5)HttpRequest.GET
一个类似于字典的对象,包含HTTP、GET的所有参数。详情请参考QueryDict对象。
(6)HttpRequest.POST
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成QueryDict对象。
POST请求可以带有空的POST字典 —— 如果通过HTTPPOST方法发送一个表单,但是表单中没有任何的数据,QueryDict对象依然会被建。
因此,不应该使用 if request.POST来检查使用的是否是POST方法;应该使用 if request.method == "POST"
另外:如果使用POST上传文件的话,文件信息将包含在FILES属性中。
(7)HttpRequest.REQUEST
一个类似于字典的对象,它首先搜索POST,然后搜索GET,主要是为了方便。灵感来自于PHP的 $_REQUEST。
例如,如果GET = {"name": "john"}而POST = {"age": '34'} , REQUEST["name"]将等于"john", REQUEST["age"]将等于"34"。
强烈建议使用GET和POST而不要用REQUEST,因为它们更加明确。
(8)HttpRequest.COOKIES
一个标准的Python字典,包含所有的cookie。键和值都为字符串。
(9)HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。
(10)HttpRequest.META
一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME 类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送的HTTP Host 头部。
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端的user-agent 字符串。
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP 地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_ 前缀。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
(11)HttpRequest.user
一个AUTH_USER_MODEL类型的对象,表示当前登录的用户。
如果用户当前没有登录,user将设置为django.contrib.auth.models.AnonymousUser的一个实例。你可以通过is_authenticated()区分它们。
例如:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user 只有当Django启用AuthenticationMiddleware中间件时才可用。
(12)HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django启用会话的支持时才可用。
(13)HttpRequest.resolver_match
一个ResolverMatch的实例,表示解析后的URL。这个属性只有在URL解析方法之后才设置,这意味着它在所有的视图中可以访问,
但是在URL解析发生之前执行的中间件方法中不可以访问(比如process_request,但你可以使用process_view代替)。
四、MTV模型
Django的MTV分别代表:
Model(模型):负责业务对象与数据库的对象(ORM)
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
1、模板层(template)
from django.conf.urls import url,include
from django.contrib import admin
from django.shortcuts import HttpResponse
from app01.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^template/', temp_func,),
]
views.py文件内容:
def temp_func(request):
l=[11,222,333]
dic={"name":"yuan","age":23}
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def learning(self):
return "learning"
alex=Person("alex",45)
egon=Person("egon",36)
person_list=[alex,egon]
import datetime
now=datetime.datetime.now()
print(now)
file_size=234212123
content="hello yuan world text"
s="<a href='http://www.baidu.com'>hello</a>"
#return render(request,"temp.html",{"l":l,"dic":dic})
return render(request,"temp.html",locals())
app01应用下创建templatetags模块(文件夹),里面创建my_filters_tags.py文件,内容如下:
@register.filter
def multi_filter(x,y):
return x * y
@register.simple_tag
def multi_tag(x,y):
return x * y
temp.html文件内容:
{% load my_filters_tags %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>变量</h3>
<p>{{ l }}</p> {# 结果是:[11, 222, 333] #}
<p>{{ l.1 }}</p> {# 结果是:222 #}
<p>{{ dic }}</p> {# 结果是:{'name': 'yuan', 'age': 23} #}
<p>{{ dic.name }}</p> {# 结果是:yuan #}
<p>{{ alex.age }}</p> {# 结果是:45 #}
<h3>过滤器</h3> {# 语法;{{obj|filter__name:param}} #}
<p>{{ l.1|add:100 }}</p> {# 结果是:322 #}
<p>{{ now|date:"Y-m-d" }}</p> {# 结果是:2018-04-16 #}
<p>{{ file_size|filesizeformat }}</p> {# 结果是:223.4 MB #}
<p>{{ content|truncatechars:12 }}</p> {# 结果是:hello yua... 加上点号一共显示12个字符 #}
<p>{{ content|truncatewords:2 }}</p> {# 结果是:hello yuan ... 显示两个单词#}
<p>{{ content|slice:"2:-1" }}</p> {# 结果是:llo yuan world tex #}
<p>{{ s|safe }}</p> {# 结果是:hello 告诉Django这段代码是安全的不必转义#}
<h3>标签</h3>
{% for person in person_list %} {# for循环person_list列表 #}
<p>{{ forloop.counter0 }} {{ person.name }}:{{ person.age }} --- {{ person.learning }}</p>
{% endfor %}
{# {{ forloop.counter0 }} 可以取到循环序号 #}
{# 如果变量l.0 > 100,就显示100,否则显示变量l.0 #}
{% if l.0 > 100 %}
<p>100</p>
{% else %}
<p>{{ l.0 }}</p>
{% endif %}
<h4>自定义过滤器或者标签</h4>
{{ l.0|multi_filter:2 }} {# 结果是:22 #}
{% multi_tag l.0|add:12 10 %} {# 结果是:230 #}
</body>
</html>
五、Django-model基础
1、在settings.py配置下面内容可以查看翻译成的sql语句
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
2、创建模型
class Author(models.Model): #Author表包含 nid、name、age、 authorDetail字段
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
# 与AuthorDetail建立一对一的关系
authorDetail = models.OneToOneField(to="AuthorDetail")
class AuthorDetail(models.Model): #AuthorDetail表包含nid、birthday、telephone、addr字段
nid = models.AutoField(primary_key=True)
birthday = models.DateField()
telephone = models.BigIntegerField()
addr = models.CharField(max_length=64)
class Publish(models.Model): #Publish表包含nid、name、city、email字段
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
class Book(models.Model): #Book表包含nid、title、publishDate、price、keepNum、publish字段
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
publishDate = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2)
keepNum = models.IntegerField() < br > commentNum = models.IntegerField()
# 与Publish建立一对多的关系,外键字段建立在多的一方
publish = models.ForeignKey(to="Publish", to_field="nid")
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
authors = models.ManyToManyField(to='Author')
3、字段选项
(1)null
如果为True,Django将用NULL来在数据库中存储空值。 默认值是False.
(2)blank
如果为True,该字段允许不填。默认为False。要注意,这与null不同。null纯粹是数据库范畴的,而blank是数据验证范畴的。
如果一个字段的blank = True,表单的验证将允许该字段是空值。如果字段的blank = False,该字段就是必填的。
(3)default
字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
(4)primary_key
如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key = True,Django就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,否则没必要设置任何一个字段的primary_key = True。
(5)unique
如果该值设置为True, 这个数据字段的值在整张表中必须是唯一的
(6)choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。
4、添加表记录
(1)普通字段
#1、方式1
publish_obj = Publish(name="人民出版社", city="北京", email="renMin@163.com")
publish_obj.save() # 将数据保存到数据库
#2、方式2 < br > 返回值publish_obj是添加的记录对象
publish_obj = Publish.objects.create(name="人民出版社", city="北京",
email="renMin@163.com") < br > < br > 方式3 < br > 表.objects.create(**request.POST.dict())
(2)外键字段
#1、方式1:
publish_obj = Publish.objects.get(nid=1)
Book.objects.create(title="西游记", publishDate="2012-12-12", price=665, pageNum=334, publish=publish_obj)
#2、方式2:
Book.objects.create(title="西游记", publishDate="2012-12-12", price=665, pageNum=334, publish_id=1)
(3)多对多字段
book_obj = Book.objects.create(title="追风筝的人", publishDate="2012-11-12", price=69, pageNum=314, publish_id=1)
author_yuan = Author.objects.create(name="yuan", age=23, authorDetail_id=1)
author_egon = Author.objects.create(name="egon", age=32, authorDetail_id=2)
book_obj.authors.add(author_egon, author_yuan) # 将某个特定的 model 对象添加到被关联对象集合中。 ======= book_obj.authors.add(*[])
book_obj.authors.create() # 创建并保存一个新对象,然后将这个对象加被关联对象的集合中,然后返回这个新对象。
解除关系:
book_obj.authors.remove() # 将某个特定的对象从被关联对象集合中去除。 ====== book_obj.authors.remove(*[])
book_obj.authors.clear() #清空被关联对象集合。
5、查询表记录
(1)查询相关API
< 1 > all(): 查询所有结果
< 2 > filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
< 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
< 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
< 5 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
< 6 > values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
< 7 > order_by(*field): 对查询结果排序
< 8 > reverse(): 对查询结果反向排序
< 9 > distinct(): 从返回结果中剔除重复纪录
< 10 > count(): 返回数据库中匹配查询(QuerySet)的对象数量。
< 11 > first(): 返回第一条记录
< 12 > last(): 返回最后一条记录
< 13 > exists(): 如果QuerySet包含数据,就返回True,否则返回False
(2)双下划线之单表查询
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
models.Tb1.objects.filter(name__contains="ven")
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
startswith,istartswith, endswith, iendswith
(3)基于对象的跨表查询
< 1 >一对多查询(Publish 与 Book)
正向查询(按字段:publish):
# 查询nid=1的书籍的出版社所在的城市<br>
book_obj=Book.objects.get(nid=1)<br>print(book_obj.publish.city) # book_obj.publish 是nid=1的书籍对象关联的出版社对象
反向查询(按表名:book_set):
# 查询 人民出版社出版过的所有书籍
publish = Publish.objects.get(name="人民出版社")
book_list = publish.book_set.all() # 与人民出版社关联的所有书籍对象集合
for book_obj in book_list:
print(book_obj.title)
< 2 >一对一查询
正向查询(按字段:authorDetail):
# 查询egon作者的手机号
author_egon = Author.objects.get(name="egon")
print(author_egon.authorDetail.telephone)
反向查询(按表名:author):
# 查询所有住址在北京的作者的姓名
authorDetail_list = AuthorDetail.objects.filter(addr="beijing")
for obj in authorDetail_list:
print(obj.author.name)
< 3 >多对多查询
正向查询(按字段:authors):
book_obj = Book.objects.filter(title="西游记").first()
authors = book_obj.authors.all()
for author_obj in authors:
print(author_obj.name, author_obj.authorDetail.telephone)
反向查询(按表名:book_set):
# 查询egon出过的所有书籍的名字
author_obj = Author.objects.get(name="egon")
book_list = author_obj.book_set.all() # 与egon作者相关的所有书籍
for book_obj in book_list:
print(book_obj.title)
#查询 人民出版社出版过的所有书籍
publish = Publish.objects.get(name="人民出版社")
book_list = publish.bookList.all() # 与人民出版社关联的所有书籍对象集合
(4)基于双下划线的跨表查询
# 练习1: 查询人民出版社出版过的所有书籍的名字与价格(一对多)
# 正向查询 按字段:publish
queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","price")
# 反向查询 按表名:book
queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__price")
# 练习2: 查询egon出过的所有书籍的名字(多对多)
# 正向查询 按字段:authors:
queryResult=Book.objects.filter(authors__name="yuan").values_list("title")
# 反向查询 按表名:book
queryResult=Author.objects.filter(name="yuan").values_list("book__title","book__price")
# 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名
# 正向查询
queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","authors__name")
# 反向查询
queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__authors__age","book__authors__name")
# 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称
queryResult=Book.objects.filter(authors__authorDetail__telephone__regex="151").values_list("title","publish__name")
# 练习1: 查询人民出版社出版过的所有书籍的名字与价格(一对多)
# 反向查询 不再按表名:book,而是related_name:bookList
queryResult = Publish.objects.filter(name="人民出版社").values_list("bookList__title", "bookList__price")
6、修改表记录
Book.objects.filter(price=123,title="python").update(title="python123")
7、删除表记录
Book.objects.filter(price=123,title="python").delete()
你也可以一次性删除多个对象。每个 QuerySet 都有一个 delete() 方法,它一次性删除 QuerySet 中所有的对象。
例如,下面的代码将删除 pub_date 是2005年的 Entry 对象:
Entry.objects.filter(pub_date__year=2005).delete()
要牢记这一点:无论在什么情况下,QuerySet 中的 delete() 方法都只使用一条 SQL 语句一次性删除所有对象,而并不是分别删除每个对象。如果你想使用在 model 中自定义的 delete() 方法,就要自行调用每个对象的delete 方法。(例如,遍历 QuerySet,在每个对象上调用 delete()方法),而不是使用 QuerySet 中的delete()方法。
在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。
例如:
b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()
转载于:https://blog.51cto.com/qidian510/2104211