一、简单演示
返回当前时间
url.py文件内容:
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^timmer/', views.timmer),]
views.py文件内容:
from django.shortcuts import render,HttpResponse,redirectdef timmer(request): import time ctime=time.time() # return HttpResponse (ctime) #只能返回字符串 return render(request,"timmer.html", {"ctime":ctime}) #返回html,这样就能定义返回的样式
timmer.html文件内容:
timmer < style > p{ color: red; } {#双大括号是模板语法,里面是变量,接受views.py的参数#}当前时间:{
{ ctime }}
二、url控制器
1、url的分组
urls.py文件内容:
from django.conf.urls import url,includefrom django.contrib import adminfrom django.shortcuts import HttpResponsefrom 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\d+)/(?P \d+)/$', books_achrive2), # books_achrive(request,year=2012,month=12)]
views.py文件内容:
from django.shortcuts import render,HttpResponse,redirectdef 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,includefrom 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\d+)/(?P \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 urlfrom . import viewsurlpatterns = [ url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),]
在模板的代码中使用下面的方法获得它们:
2012 Archive{% for yearvar in year_list %}
- { { yearvar }} Archive
{% endfor %}
(2)在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
from django.core.urlresolvers import reversefrom django.http import HttpResponseRedirectdef 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,includefrom django.contrib import adminfrom django.shortcuts import render,HttpResponse,redirectfrom 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,redirectdef 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文件内容:
Title
利用反向解析的好处:访问的时候用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,includefrom django.contrib import adminfrom django.shortcuts import HttpResponsefrom 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=" hello" #return render(request,"temp.html",{"l":l,"dic":dic}) return render(request,"temp.html",locals())
app01应用下创建templatetags模块(文件夹),里面创建my_filters_tags.py文件,内容如下:
@register.filterdef multi_filter(x,y): return x * y@register.simple_tagdef multi_tag(x,y): return x * y
temp.html文件内容:
{% load my_filters_tags %}Title 变量
{
{ l }} {# 结果是:[11, 222, 333] #}{
{ l.1 }} {# 结果是:222 #}{
{ dic }} {# 结果是:{'name': 'yuan', 'age': 23} #}{
{ dic.name }} {# 结果是:yuan #}{
{ alex.age }} {# 结果是:45 #}过滤器
{# 语法;{ {obj|filter__name:param}} #}{
{ l.1|add:100 }} {# 结果是:322 #}{
{ now|date:"Y-m-d" }} {# 结果是:2018-04-16 #}{
{ file_size|filesizeformat }} {# 结果是:223.4 MB #}{
{ content|truncatechars:12 }} {# 结果是:hello yua... 加上点号一共显示12个字符 #}{
{ content|truncatewords:2 }} {# 结果是:hello yuan ... 显示两个单词#}{
{ content|slice:"2:-1" }} {# 结果是:llo yuan world tex #}{
{ s|safe }} {# 结果是:hello 告诉Django这段代码是安全的不必转义#}标签
{% for person in person_list %} {# for循环person_list列表 #}{
{ forloop.counter0 }} { { person.name }}:{ { person.age }} --- { { person.learning }}{% endfor %}{# { { forloop.counter0 }} 可以取到循环序号 #}{# 如果变量l.0 > 100,就显示100,否则显示变量l.0 #}{% if l.0 > 100 %}100
{% else %}{
{ l.0 }}{% endif %}自定义过滤器或者标签
{ { l.0|multi_filter:2 }} {# 结果是:22 #}{% multi_tag l.0|add:12 10 %} {# 结果是:230 #}
五、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 inmodels.Tb1.objects.filter(name__contains="ven")models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen andstartswith,istartswith, endswith, iendswith
(3)基于对象的跨表查询
< 1 >一对多查询(Publish 与 Book)
正向查询(按字段:publish):# 查询nid=1的书籍的出版社所在的城市book_obj=Book.objects.get(nid=1)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()