视图层

1. 昨日回顾

查询数据
	get()
	filter()
	all() 
创建数据
	create()
	
	user_obj = models.Userinfo(**kwargs)
	user_obj.save()
		
数据的编辑与删除
	后端如何获取前端用户想要编辑的数据对象
    1.利用get请求url后面可以携带参数的方式 将数据的主键值传递给后端
	编辑功能的思路:获取用户想要编辑的数据对象 展示到前端页面 用户修改之后点击修改 再去修改数据库中对应的数据
		1.方式1
        modeles.Userinfo.objects.filter(**kwargs).update()  # 批量更新
		2.方式2  (不推荐使用 效率极低 会将每一个字段对应的值全部重写一遍)
        edit_obj = models.Userinfo.objects.filter(pk=edit_id).first()  # pk会自动帮你查找当前表的主键字段
        edit_obj.username = username
        edit_obj.password = password
        edit_obj.save()  
        
删除
	models.Userinfo.objects.filter(pk=delete_id).delete()
	"""真正的数据是不会被删除的 通常都是给数据设置一个是否删除的标志位"""

图书管理系统表设计(orm如何创建表与表之间的关系)
一对多:一对多外键字段应该建在多的那一方
	models.ForeignKey(to='关联的表名')  # 自动建关系 默认就是跟关联表的主键字段
"""ForeginKey字段在创建的时候 orm会自动在字段后面加_id"""
            
多对多
	ManyToManyField(to='关联的表名')  # 并不会创建一个实际字段 仅仅是用来告诉django orm自动创建第三张表
            
一对一
	OneToOneField(to='关联的表名')
	"""OneToOneField字段在创建的时候 orm会自动在字段后面加_id"""

django请求生命周期流程图
        
路由层
	路由匹配: url第一个参数是正则
	无名分组: url(r'^index/(d+)/',views.index)
    	在调用视图函数index的时候 会将d+匹配到的内容 当做位置参数传递给index
	有名分组: url(r'^index/(?P<year>d+)/',views.index)
        在调用视图函数index的时候 会将d+匹配到的内容 当做关键字参数(year='')传递给index
	"""注意 无名有名不能混合使用 但是可以单独使用 单独使用的时候支持多个"""
	反向解析
		本质:根据某一个东西得出一个结果  该结果可以直接访问到对应的url
            
	没有正则表达式的反向解析
		url(r'^index/',views.index,name='xxx')  # 起别名 别名一定不要重复
      	前端反向解析: {% url 'xxx' %}
      	后端反向解析: 
      	from django.shortcuts import reverse
			url = reverse('xxx')
	
	无名和有名分组的反向解析: url(r'^index/(d+)/',views.index,name='xxx')
		前端反向解析: {% url 'xxx' 123 %}
        后端反向解析: 
        	from django.shortcuts import reverse
				url = reverse('xxx',args=(123,))
        """个人建议:在处理容器类型数据的时候 无论有几个值 你最后都加一个逗号"""
                    
     url(r'^index/(?P<year>d+)/',views.index,name='xxx')
		前端反向解析: {% url 'xxx' 123 %}
                    {% url 'xxx' year=123 %}  # 了解
        后端反向解析: 
			from django.shortcuts import reverse
                url = reverse('xxx',args=(123,))
                url = reverse('xxx',kwargs={'year':123})  # 了解
		"""个人建议:在处理容器类型数据的时候 无论有几个值 你最后都加一个逗号"""
                
	路由分发
        django中的每一个app都可以有自己独立的static文件夹,templates文件夹,urls.py等
        正是由于上述的特点 你基于django开发项目 就真正可以做到分组分功能分模块独立的去开发
        当应用特别多的时候 总路由中的代码过于冗长 不好维护
        # 1.在应用下自己手动创建urls.py
        # 2.在路由中导入 
        	# 1
            from app01 import urls as app01_urls
            from app02 import urls as app02_urls
                
            url(r'^app01/',include(app01_urls)),
            url(r'^app02/',include(app02_urls))
            # 2
            url(r'^app01/',include('app01.urls')),
            url(r'^app02/',include('app02.urls'))  
            
	名称空间
	url(r'^app01/',include('app01.urls',namespace='app01')),
                url(r'^app02/',include('app02.urls',namespace='app02')) 
     
     # app01 urls.py
     url(r'^index/',views.index,name='index')
     # app02 urls.py
     url(r'^index/',views.index,name='index')
                
     url = reverse('app01:index')
     url = reverse('app02:index')
     {% url 'app01:index' %}
     {% url 'app02:index' %}
                
      # app01 urls.py
		url(r'^index/',views.index,name='app01_index')
      # app02 urls.py
        url(r'^index/',views.index,name='app02_index')
                
		
伪静态
	url看起来像是一个静态页面(.html结尾)
        
虚拟环境
    不同的项目应该有各自独立的解释器环境 最大化节省资源
    实际功能中针对不同的项目 会有一个叫requestsments.txt文件
    该文件中列出来是一个个该项目需要用的到模块名和版本号
    eg:
		django = 1.11.11
        nginx = 1.21
	后期通过命令直接会去下载该文件内所有的模块及对应版本
        
	虚拟环境 就类似于是个python解释器环境 每创建一个就类似于重新下载了一个纯净的python解释器环境
     
django版本区别
	url和path
        path第一个参数不支持正则 写什么就匹配什么 精准匹配
        re_path跟url是一模一样的用法   
    提供五个默认的转换器  
    还支持用户自定义转换器

2. 视图层

# 1.HttpResponse  # 返回字符串
            
# 2.render  # 返回一个html页面 还可以给模板传递
# render的内部原理
from django.template import Template,Context

def index(request):
	res = Template("<h1> {{ user }} </h1>")
	con = Context({'user':{'username':'jason','pwd':'123'}})
	ret = res.render(con)
	print(ret)
	return HttpResponse(ret)
# 3.redirect  # 重定向

3. JsonResponse

# JsonResponse: 返回json格式数据的
'''
为什么要给前端返回json格式字符串
前后端分离  就是基于json格式传输数据
后端就专门写接口 前端调用你这个接口 就能够拿到一个
json格式的字符串
然后前端利用序列化反序列转换成前端对应的数据类型

js常用数据类型: 数值类型、字符类型、数组 []、自定义对象 {}、undefined与null、布尔值 true false、symbol(新加的)

JSON.stringify 序列化   >>>   json.dumps
JSON.parse     反序列   >>>   json.loads
'''
def index(request):
    # user = {'username': 'aa哈哈哈', 'pwd': '123'}
    # json_str = json.dumps(user, ensure_ascii=False)
    # return HttpResponse(json_str)
    # return JsonResponse(user,json_dumps_params={'ensure_ascii':False})

    l = [1,2,3,4,5,6]
    return JsonResponse(l, safe=False)
    # JsonResponse默认只支持序列化字典 如果你想序列化其他类型(json能够支持的类型) 你需要将safe参数由默认的True改成False

4. form表单上传文件

'''
注意事项:
	1.提交方式必须是post
	2.enctype参数必须有默认的urlencoded变成formdata
	
FBV与CBV 即CBV源码分析
	FBV(Function Based View) 基于函数的视图
    CBV(Class Based View) 基于类的视图
    
思考:你在类中写了两个方法 一个叫get一个叫post
     为什么前端get请求来就会触发get方法
     post请求来就会触发post方法  如何实现的???
'''

# 上传文件
def up(request):
    if request.method == 'POST':
        # 获取文件对象
        file_obj = request.FILES.get('myfile')
        with open(file_obj.name,'wb') as f:   # file_obj.name 获取文件名
            for chunk in file_obj.chunks():
                f.write(chunk)
    return render(request,'up.html')


# CBV路由
url(r'^reg/',views.MyReg.as_view())
        
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
	self = cls(**initkwargs)  # cls就是我们自己的写的MyReg类
    if hasattr(self, 'get') and not hasattr(self, 'head'):
    	self.head = self.get
    self.request = request
    self.args = args
    self.kwargs = kwargs
    # 上面的一通操作 就是给我们自己写的类的对象赋值
    return self.dispatch(request, *args, **kwargs)
    # 对象在查找属性或方法的时候 顺序是什么?  先从自己找 再从产生对象的类中找  再去类的父类中找...
    """也就意味着你在看源码的时候 你一定要牢记上面的话"""
return view
        
# views.py 
from django.views import View


class MyReg(View):
	def get(self,request):
		return render(request,'reg.html')

	def post(self,request):
        return HttpResponse("我是MyReg类中post方法")
        
"""CBV最精髓的部分"""
def dispatch(self, request, *args, **kwargs):
	if request.method.lower() in self.http_method_names:  # 判断当前请求方式在不在默认的八个请求方式中
		handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        # handler = getattr(自己写的类产生的对象,'小写的请求方法(getpost)','获取不到对应的方法就报错')
        # handler就是我们自己定义的跟请求方法相对应的方法的函数内存地址
	else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)  # 在调用获取到的方法

5. django settings源码分析及实际应用

'''
django的配置文件有两个
一个是暴露给用户可以自定义配置的
一个是默认的全局配置文件
用户指定了就用用户的
用户没有指定就用默认的
'''
from django.conf import settings

settings = LazySettings()
        
class LazySettings(LazyObject):
            
def _setup(self, name=None):
	# os.environ你可以把它看成是一个全局的大字典
    settings_module = os.environ.get(ENVIRONMENT_VARIABLE)  # 从大字典中取值
	# settings_module = 'day59.settings'
	self._wrapped = Settings(settings_module)  # Settings('day59.settings')
        
class Settings(object):
	def __init__(self, settings_module):  # settings_module = 'day59.settings'
		for setting in dir(global_settings):  # 循环获取global_settings文件中所有的名字
			if setting.isupper():  # 在判断名字是否是大写
				# 如果是大写 利用反射 获取到大写的名字所对应的值  不停地添加到对象中
				setattr(self, setting, getattr(global_settings, setting))
		# store the settings module in case someone later cares
        self.SETTINGS_MODULE = settings_module
        mod = importlib.import_module(self.SETTINGS_MODULE)  # 'day59.settings'
        # from day59 import settings
        # mod 指代的就是暴露给用户的配置文件模块名
               
        for setting in dir(mod):  # 循环获取暴露给用户配置文件中所有的名字
			if setting.isupper():  # 判断是否是大写
            setting_value = getattr(mod, setting)  # 如果是大写 获取大写的变量名所对应的值
            setattr(self, setting, setting_value)  # 不停的给对象设置值
        

6. 模板传值

# 如果传递给前端一个函数名,会直接加括号调用,将函数的返回值展示到前端,django的模板语法不支持给函数传参
<p>{{ func }}</p>

# 方法都不能传参
<p>{{ obj }}</p>
<p>{{ obj.get_cls }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_self }}</p>

# django模板语法在获取容器类型内部元素的值的时候 统一只采用 句点符(.)
# 模板语法取值
<p>{{ l.1 }}</p>
<p>{{ l.3 }}</p>
<p>{{ d.username }}</p>
<p>{{ d.password }}</p>
<p>{{ d.password.1 }}</p>

7. 过滤器与标签

'''
1.过滤器(|)
(前端代码并不一定非要在前端写  你也可以在后端写好 传递给前端页面)
    前后端取消转义
        前端 
            |safe
        后端
            from django.utils.safestring import mark_safe
            sss2 = "<a href='http://www.xiaohuar.com'>下午上课 需要激情</a>"
            res = mark_safe(sss2)

    模板语法的符号就两种
        {{}}  变量相关
        {%%}  逻辑相关
'''
{#过滤器 有点类似于小的方法  #}
{#特点 会将|左边的当做过滤器的第一个参数  |右边的当前过滤器第二个参数#}
<p>{{ n|add:100 }}</p>
<p>{{ n|add:'abc' }}</p>   {# 返回空 #}
<p>{{ s|add:'abc' }}</p>
<p>{{ l|length }}</p>
<p>{{ d|length }}</p>

<p>{{ file_size|filesizeformat }}</p>

<p>截取10个字符 三个点也算{{ w|truncatechars:10 }}</p>
<p>截取10个字符 三个点也算{{ w1|truncatechars:10 }}</p>
<p>安装空格截取单词 三个点不算{{ w|truncatewords:6 }}</p>
<p>安装空格截取单词 三个点不算{{ w1|truncatewords:6 }}</p>
<p>安装空格截取单词 三个点不算{{ w2|truncatewords:6 }}</p>

<p>{{ l|slice:'0:5' }}</p>
<p>{{ l|slice:'0:5:2' }}</p>

<p>{{ ctime|date:'Y-m-d' }}</p>
<p>{{ ctime|date:'Y年m月d日' }}</p>

<p>{{ sss|safe }}</p>
<p>{{ sss1|safe }}</p>
<p>{{ res }}</p>

<p>{{ xo|default:'' }}</p>
{#有值就拿值 没值就用后面默认的#}

    
# 2.标签
	# if判断
	# for循环
{% for foo in l %}
    {% if forloop.first %}
        <p>第一次</p>
    {% elif forloop.last %}
        <p>最后一次</p>
    {% else %}
        <p>嗨起来</p>
    {% endif %}
{% endfor %}
	
# 3.自定义过滤器、标签的步骤
	# 1.在应用名下面新建一个templatetags文件夹(必须叫这个名字)
	# 2.在该文件夹下新建一个任意名称的py文件
	# 3.在该pa文件内固定写两行代码
    	from django.template import Library
        register = Library()
	
# 4.自定义的过滤器
	@register.filter(name='myfilter')
    def index(a,b):
        return a + b
		
# 5.自定义的标签
	@register.simple_tag(name='myst')
    def login(a,b,c,d):
        return f'{a}{b}{c}{d}'
    
# 6.区别 标签不能再if中使用
# 可以用
{% if 0|myfilter:123 %}
    <p>有值</p>
{% endif %}

# 不能用
{#{% if myst 1 2 3 4 5 %}#} 
{#    <p>有值</p>#}
{#{% endif %}#}

8. 模板的继承

# 事先需要再模板中 通过block划定区域
    {% block 区域名字 %}

    {% endblock %}

# 子板中如何使用
    {% extends '模板的名字'%}

    {% block 区域名字 %}
    <h1>登录页面</h1>
    {% endblock %}

# 一个页面上 block块越多 页面的扩展性越高
# 通常情况下 都应该有三片区域
    {% block css %}
    {% endblock %}

    {% block content %}
    {% endblock %}

    {% block js %}
    {% endblock %}

# 子板中还可以通过 {{ block.super }} 来继续使用母版的内容

9. 模板的导入

# 当你写了一个特别好看的form表单 你想再多个页面上都使用这个form表单,你就可以将你写的form表单当作模块的形式导入 导入过来之后 就可以直接展示
	{% include 'good_page.html' %}
原文地址:https://www.cnblogs.com/yushan1/p/11729162.html