草稿一

● urlpatterns = [
path('',index),
...
]

这里的''留空,相对应的地址就是:127.0.0.1:8000

● 'python包'和'目录(文件夹)'的区别:'python包'里面多了'init.py'

● 所谓的'django模型',就是数据库中的一张表

● 重启项目快捷方式---'ctrl+s';批量注释的快捷键:'ctrl+/'

● from django.http import HttpResponse:鼠标移动到HttpResponse,ctrl+B可以查看源码(点击'structure'可以查看更多源码结构)

● 使用'<>'来接收用户输入的url:
示例:

def front_user(request,user_id): # 注意这里的user_id类型是str,而不是int
text='your user_id is {}'.format(user_id)
return HttpResponse(text)

urlpatterns=[
...
path('user/',views.front_user),
]

访问:http://127.0.0.1:8000/front/user/1,返回: your user_id is 1

● 查询字符串:以'?'开头,例如百度的'?wd=python',而其实质,就是get请求
在django操作中,url无需做多余的配置,view这么写:

对查询字符串进行判断,实现页面跳转的demo

from django.shortcuts import render,redirect,reverse
from django.http import HttpResponse

def cms_index(request):
query_string=request.GET.get('username') # query_string=request.GET['username']
if query_string:
return HttpResponse("This is a cms index page.")
else:
print(''30)# 启动项目,访问这个url,可以在终端查看效果
# 这里reverse的作用,传入name名,获取url
print(reverse('cms_login'))
print('*' * 30)
return redirect(reverse('cms_login'))
'''


/cms/login


'''

review 示例:

from django.shortcuts import render,redirect,reverse
from django.http import HttpResponse

def get_query_string(request):

username=request.GET.get('username') # 获取用户输入的关键词
local_url='?username='+username # 手动拼接url并输出
print(local_url)

if username:
    return HttpResponse('Hello {},welcome to the person page.'.format(username))
else:
    query_url=reverse('get_query_string')
    print('*'*40)
    print(query_url)

    login_url=reverse('person_login')
    return redirect(login_url)

def person_login(request):
return HttpResponse('This is person login page.')

• url命名---name

from django.urls import path
from . import views

urlpatterns=[
path('index',views.cms_index,name='cms_index'),
path('login',views.cms_login,name='cms_login')
]

若没有name这个参数,那么一旦网址发生变更,不仅view,url需要修改,而且前端HTML文档也需要修改,非常麻烦又易出错.

app命名:若有2个app的url name 参数值一样,django会混乱,所以引入'app_name'这个参数,防止出现name参数同名而出现的url错误
示例:

cms.urls

from django.urls import path
from . import views

app_name='cms' # 添加app_name参数

urlpatterns = [
path('index',views.index,name='index'),
path('login',views.login,name='login'),

]

cms.views

from django.shortcuts import render,redirect,reverse
from django.http import HttpResponse

def index(request):
query_string = request.GET.get('username')
if query_string:
return HttpResponse("This is a cms index page.")
else:
print('' * 30)
print(reverse('cms:login')) # 注意此时的格式
print('
' * 30)
return redirect(reverse('cms:login')) # 注意此时的格式

front.urls.py

from django.urls import path
from . import views

app_name='front' # 添加app_name参数

urlpatterns = [
path('index', views.index,name='index'),
path('login', views.login,name='login'),
]

front.views

from django.shortcuts import render,reverse,redirect
from django.http import HttpResponse

def index(request):
query_string = request.GET.get('username')
if query_string:
return HttpResponse("This is a front index page.")
else:
print('' * 30)
print(reverse('front:login')) # 反转url格式
print('
' * 30)
return redirect(reverse('front:login'))

• 实例命名空间 namespace --- 属于 include()函数的参数

一个app可以创建多个实例,也就是说,可以使用多个url映射到同一个app
这就会产生一个问题:以后在做反转的时候,如果使用应用命名空间,那么就会发生混淆
示例:

main_url.py

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
path('admin/', admin.site.urls),
path('front/',include('front.urls')),
path('cms1/',include('cms.urls'),), # cms1,cms2两个实例均映射到同一app:cms
path('cms2/',include('cms.urls')),

]

首先,访问:http://127.0.0.1:8000/cms1/index
跳转到:http://127.0.0.1:8000/cms1/login # 没毛病

再来,访问:http://127.0.0.1:8000/cms2/index
跳转到:http://127.0.0.1:8000/cms1/login # 显然就有问题了

现在使用实例命名空间---namespace参数

main_url

urlpatterns = [
...
path('cms1/',include('cms.urls',namespace='cms1'),),
path('cms2/',include('cms.urls',namespace='cms2')),

]

cms.views

from django.shortcuts import render,redirect,reverse
from django.http import HttpResponse

def index(request):
query_string = request.GET.get('username')
if query_string:
return HttpResponse("This is a cms index page.")
else:
# 获取实例命名空间
current_namespace=request.resolver_match.namespace
# 使用实例命名空间做url跳转
return redirect(reverse('{}:login'.format(current_namespace))) # 这里如果把{}写死,显然不能达到目的,所以只能动态获取

小结:

<1>url反转---reverse('login'):反向解析域名,避免硬编码url
<2>应用空间命名:app_name='cms':避免不同app之间的name参数同名
<3>实例空间命名:include('cms.urls',namespace='cms1'),避免映射同一app的实例的url出现混乱

redirect和reverse的区别,示例:

main_url

...
path('book/login',book_views.login,name='book_login'),
path('book/',book_views.index,name='book_index'),

book.views

from django.shortcuts import render,reverse,redirect
from django.http import HttpResponse

def index(request):
return HttpResponse('index page')

def login(request):
username=request.GET.get('username')
if username:
return HttpResponse('login page')
else:
print(''40)
print(redirect('book_index'))
print(type(redirect('book_index'))) #
print('*' * 40)
print(reverse('book_login'))# /book/login
print(reverse('book_index'))# /book/
return redirect('book_index')

结果:

'''


...


/book/login
/book/

'''
结论:同样都是接收name名,reverse()返回的是普通的url字符串;redirect()返回的是一个'重定向的类'
当url只有一个name参数(或者有app_name参数)的时候,使用以下代码是没有区别的,都能实现效果:
return redirect('book_index')
return redirect(reverse('book_index'))

但是,reverse()不仅可以接收'appname:name'的形式,还可以接收'namespace:name'的形式,示例:

main_url

from django.contrib import admin
from django.urls import path,include
from front import views as front_views
from book import views as book_views

urlpatterns = [
...
#path('book/',include('book.urls')),
path('book1/',include('book.urls',namespace='book1')),
path('book2/',include('book.urls',namespace='book2')),
]

book.urls

from django.urls import path
from . import views

app_name='book'

urlpatterns = [
path('login/',views.login,name='login'),
path('',views.index,name='index'),
]

book.views

def login(request):
username=request.GET.get('username')
if username:
return HttpResponse('login page')
else:
namespace=request.resolver_match.namespace
print(namespace) # book2
print(''40)
url=reverse('{}:index'.format(namespace)) # /book2/ # 使用reverse的'namespace:name'形式获取动态的namespace
print(url)
#return redirect('book:index') # 这里若采用'appname:name'形式,无法实现url的动态跳转
return redirect(url)

小结:需要url跳转的时候,最好使用return redirect(reverse())的形式,这种形式'无视各种'name参数

● url转换器,先看示例:

def front_user(request,user_id):
text='your user_id is {}'.format(user_id)
return HttpResponse(text)

urlpatterns=[
...
path('user/',views.front_user) #
]

这种写法表明,只接收用户输入int类型的url,此时若输入str(比如输入'jim'),就报错.
我们导入转换器,查看源码类型:

from django.urls import converters # Ctrl+b

class IntConverter: # int
regex = '[0-9]+' # 只接收1-9的一个或者多个数字
...

url默认的接受用户输入的类型,就是str

class StringConverter: # str
regex = '[^/]+' # 除了反斜杠,其他字符串一律都可以
...

class UUIDConverter:
regex = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
...

class SlugConverter(StringConverter):
regex = '[-a-zA-Z0-9_]+'

class PathConverter(StringConverter):
regex = '.+'

● include的三种用法:

最常见的用法,用来包含app的url路径

<1>path('front/',include('front.urls')),

include的第一个参数可以是元组,包含子url文件名和app_name,第二个参数是namespace参数

<2>path('test_include/',include(('test_include.urls','test_include'),namespace='test_include'), # 推荐写法

<3>接受path_list,示例:

urlpatterns = [

# 这么写,无需在app下面,再新建urls.py了,在这已经完成了...
path('test_include/',include([
    path('index',views.include_index),
    path('book',views.include_book),
])),

● reverse用法
reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)

<1>传入path()的name参数:

main_url

urlpatterns = [
path('admin/', admin.site.urls),
path('',views.front_index,name='front_index'),
path('login/',views.front_login,name='front_login'),
path('article/',views.front_article,name='front_article_id'),
]

app.views

def front_index(request):
username=request.GET.get('username')
if username:
return HttpResponse('Hello {},it is front index page.'.format(username))
else:
return redirect(reverse('front_login')) # 传入name值

<2>增加kwargs参数(就是'kwargs=dict()'),作用在于,比如需要输入额外的url参数,此时按照<1>的做法,就报错

def front_index(request):
username=request.GET.get('username')
if username:
return HttpResponse('Hello {},it is front index page.'.format(username))
else:
return redirect(reverse('front_article_id',kwargs=dict(article_id=3))) # http://127.0.0.1:8000 跳转

def front_article(request,article_id):
return HttpResponse('The article_id is {}'.format(article_id))

注意,若使用reverse跳转网址,涉及到'查询字符串参数'的,则需手动拼接,示例:

def front_index(request):
username=request.GET.get('username')
if username:
text='Hello {},it is front index page.'.format(username)
return HttpResponse(text)
else:
#url=reverse('front_article_id',kwargs=dict(article_id=3))
query='?username=jimgreen'
url = reverse('front_login')+query # 127.0.0.1:8000 跳转到 http://127.0.0.1:8000/login/?username=jimgreen
return redirect(url)

●re_path和path:没有特别需求,使用path足够了;若涉及正则的,就使用re_path
示例:

main_url

urlpatterns = [
......
path('article/',views.front_article,name='front_article_id'),
re_path(r'^movie/(?P\d{4})/$',views.front_movie),
]

r'^/$'

app.views

def front_movie(request, year):
return HttpResponse('The year of movie is {}'.format(year))

访问:http://127.0.0.1:8000/movie/2019/

url若不是输入4位数(比如3位或5位),则找不到url了,因为在url正则里面作了严格的限制了
类似'动态url'这样的需求,一般都使用re_path()实现,例如现在有个需求是这样:

'article/python'
'article/python+django'
'article/python+django+js'
...

views

def article_list(request,categories):
text='你的文章列表是{}'.format(categories)
return HttpResponse(text)

main_url

urlpatterns = [
path('admin/', admin.site.urls),
path('',views.index),
path('article/',include('article.urls')),
]

app.url

from django.urls import re_path
from . import views

urlpatterns = [
# 注意正则中,有一个表示'或者'的符号'|'
re_path(r'(?P(\w+|+\w+)+)',views.article_list),
]

现在无论访问哪一个url,上述url均满足需求
小结:构建动态url,一般都是使用正则实现,至于正则要写在url里,还是自定义url转换器,看实际的情况


★ 自定义url转换器

相信之前已经了解到过一些django内置的url转换器,包括有int、uuid,等。 有时候这些内置的url转换器并不能满足我们的需求,因此django给我们提供了一个接口可以让我们自己定义自己的url转换器。

自定义url转换器按照以下五个步骤来走就可以了:

1.定义一个类,直接继承自object就可以了.
2.在类中定义一个属性regex,这个属性是用来限制url转换器规则的正则表达式。
3.实现to_python(self ,value)方法,这个方法是将ur1中的值转换一下, 然后传给视图函数的。
4.实现to_url(self,value)方法,这个方法是在做ur1反转的时候,将传进来的参数转换后拼接成一个正确的url。
5.将定义好的转换器,使用django.urls.converters.register_converter 方法注册到django中。

比如需求:
实现一个获取文章列表的demo,用户可以根据/articles/文章分类/的方式来获取文章。其中文章分类采用的是“分类1+分类2+分类3..."的方式拼接的,并且如果只有一个分类,那就不需要加号。示例如下:

  1. 第一种:获取python分类下的文章
    /articles/python/

2.第二种:获取python和django分类下的文章
/articles/python+django/

3.第三种:获取python和django和flask分类下的文章
/articles/python+django+flask/
以此类推...

在“文章分类”参数传到视图函数之前要把这些分类分开来存储到列表中。比如参数是“python+django",那么传到视图函数的时候就要变成“[ 'python', 'django']”,以后在使用reverse反转的时候,限制传递“文章分类”的参数应该是一个列表,并且要将这个列表变成“python+django"的形式。

示例之前,先 review str和list之间的转换,示例:

string='python+django+flask'

不管是split()还是join(),都是str的方法

string=string.split('+')# string以'+'进行拆分,并返回list
string
['python', 'django', 'flask']
list_string=string
list_string
['python', 'django', 'flask']
'+'.join(list_string) # 把字符串'+'添加进list,并返回str
'python+django+flask'

代码如下:

定义一个converter.py文件

from django.urls import converters,register_converter

class CategoryConverter:
regex = r'\w+|(\w++\w+)+'

def to_python(self, value):
    value=value.split('+')
    return value

def to_url(self, value):
    if isinstance(value,list):
        value='+'.join(value)
        return value
    else:
        raise RuntimeError('category转换类型失败')

register_converter(CategoryConverter,'cate') # 注册类,并且指定在url中的名称

在该app目录下的init.py文件中注册converter.py文件,否则该文件永远不会获得执行:

init.py

from . import converter

main_url

urlpatterns = [
...
path('article/',include('article.urls') ),
]

app_url

from django.urls import path,converters
from . import views

urlpatterns = [
path('',views.index),
path('list/',views.article_list,name='categories'),
path('detail/',views.article_detail,name='detail'),
]

app_views

from django.shortcuts import render,reverse
from django.http import HttpResponse

def index(request):
return HttpResponse('It is article index page.')

def article_list(request,categories):
text='You enter article list {}.'.format(categories)
url=reverse('categories', kwargs=dict(categories=categories))
print(url) # /article/list/python+django+c
return HttpResponse(text) # You enter article list ['python', 'django', 'c'].

def article_detail(request,article_id):
reverse('detail',kwargs=dict(article_id=article_id))
return HttpResponse('Article detail page.')

小结:自定义这种url转换器,从可读性来说,比直接使用re_path()直观

★ url视图传递默认的参数:适用两个url都调用同一个视图的场景

app.views

def article_detail(request,article_id=1): # 定义article_id默认值为'1'
reverse('detail',kwargs=dict(article_id=article_id))
return HttpResponse('Article detail page.')

app.urls

urlpatterns = [
...
path('detail/',views.article_detail), # 两个url都调用同一个视图,这个url没有传参★
path('detail/',views.article_detail,name='detail'), # 传参url
]

效果:

http://127.0.0.1:8000/article/detail/ # 访问成功

http://127.0.0.1:8000/article/detail/3 # 访问成功


模板系统

★ 加载Html文档
项目根目录下,新建'templates'文件夹,settings设置如下:

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# DIRS的模板优先级最高
'DIRS': [os.path.join(BASE_DIR, 'templates')] # 原先的配置是这样'DIRS': []
,
'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',
],
},
},
]

新建frontapp,视图如下:

from django.shortcuts import render
from django.http import HttpResponse
from django.template.loader import render_to_string

def index(request):
# 不仅把html文档转换成string,并且添加了CSS样式以后,也具有CSS样式的效果
string=render_to_string('index.html')
return HttpResponse(string)

urls

from django.contrib import admin
from django.urls import path
from front import views

urlpatterns = [
path('admin/', admin.site.urls),
path('',views.index),
]

index.html





Front index page



This is an index page.

>

使用render便捷封装---render(request, template_name, context=None, content_type=None, status=None, using=None)

views

def index(request):
# 第一个参数必须是request
return render(request,'index.html')

★ 渲染变量---{{ var }},这里的 var 名称必须和dict里的key名称保持一致,这样才能够映射正确的值(value)
基础示例:

views

def index(request):

# context接收的类型是dict
return render(request,'index.html',context=dict(username=Jim Green))

index.html


This is an index page.

>

Your username is {{ username }}

# 传到html文档里,注意语法

• 使用'.'访问属性示例:

views

from django.shortcuts import render
from django.http import HttpResponse
from django.template.loader import render_to_string

class Person():
def init(self,username):
self.username=username

def index(request):
p=Person('Kate Green')
return render(request,'index.html',context=dict(person=p))

index.html


This is an index page.

>

Your username is {{ person.username }}

# 这里的person,是字典的键名.使用'.'号进行访问

• 避免使用字典的属性和方法命名,比如使用keys作为context键名,那么文档里面{{ keys }}
会不会返回所有的键名?答案是不会...

● 常用的模板标签示例

• if基础示例:

views

def index(request):

context={
    'age':16 # age映射的值作出调整,使html文档呈现不同的文字
}
return render(request,'index.html',context=context)

html





Front index page



{% if age < 18 %}

Your age is less than 18.


{% elif age == 18 %}

Your age is 18.


{% else %}

Your age is more than 18.


{% endif %}

• if ... in ...示例:

views

def index(request):

context={
    'books':[
        'xiyouji',
        'hongloumeng',
        'shuihuzhuan',
        'sanguoyanyi',
    ]
}
return render(request,'index.html',context=context)

html


{% if 'xiyouji' in books %}

xiyouji exists


{% else %}

xiyouji don't exist


{% endif %}

• for基础示例:

views

def index(request):

context={
    'books':[
        'xiyouji',
        'hongloumeng',
        'shuihuzhuan',
        'sanguoyanyi',
    ]
}
return render(request,'index.html',context=context)

html



    {% for book in books reversed %} # 添加reversed,倒序遍历
  • {{ book }}
  • # 注意语法,如果写成book,那就遍历出4个book了
    {% endfor %}

效果:

•sanguoyanyi
•shuihuzhuan
•hongloumeng
•xiyouji

• 遍历字典示例:

views

def index(request):

context={
    'books':[
        'xiyouji',
        'hongloumeng',
        'shuihuzhuan',
        'sanguoyanyi',
    ],
    'person':{
        'username':'Jim Green',
        'age':20,
        'sex':'man'
    }
}
return render(request,'index.html',context=context)

html

    {% for p in person %} # person指代字典:{{ person }}---{'age': 20, 'sex': 'man', 'username': 'Jim Green'}
  • {{ p }}
  • {% endfor %}

效果:

•age
•sex
•username

可以看出,遍历了字典的键,一样的效果还可以这么写:

    {% for key in person.keys %} # 注意这种字典的遍历方法
  • {{ key }}
  • {% endfor %}

还可以使用dict.values(字典的值),dict.items(返回的键对的元组),示例:
# 遍历所有的键值对


    {% for k,v in person.items %}
  • {{ k }}---{{ v }}

  • {% endfor %}

'''
sex---woman
age---18
name---Kate Green
'''

你可能感兴趣的:(草稿一)