django的url分发封装
url的分发与封装基础版
组件和应用App的区别,组件其不仅服务于当前项目,其还可以服务于其他项目,即可以重复使用,
路由分发的格式,路由器分发path()中第二个参数可以是视图方法,也可以是路由分发,传一个元祖,第一个数据是路径匹配用[]括起来路径,第二,第三个是None,path里面还可以嵌套,即可以分发若干路径
urlpatterns = [ path('admin/', admin.site.urls), re_path('ad/',([ path('test/',test), path('test2/',test), ],None,None)),
对url的分发进行封装
相关概念理解
第一首先得理解app注册的含义是什么
'Xadmin.apps.XadminConfig',
其注册含义就是执行app应用下面app.py文件下面的方法,当django启动的时候就开始执行方法以及函数,此外还有一个函数
from django.utils.module_loading import autodiscover_modules
class XadminConfig(AppConfig): name = 'Xadmin' def ready(self): autodiscover_modules('Xadmin') #在App里面一定会执行的函数,扫描当前项目所有app,并执行括号里面的py文件
因此当某个项目像用到组件功能时,就引入该组件即可,所以把想要执行或者加载模块,就放在组件中 ,即Xadmin中的apps文件下,注意注册顺序
第二步函数设定与self的理解,切记,self指的是调用该类的对象
路由分发
第三步路径是django启动的时候就已经生成了,path()中的第二个参数必须是一个变量名
在A类中形成这样的路径 re_path('app01/blog',ModelXadmin(Blog,site).url) re_path('app01/article',ModelXadmin(Article,site).url) 然后在B类中再次计算路径分发 假如是ModelXadmin(Article,site).url调用url,那么在B类中的self指的就是此时实例化的对象,self.model=Aritcle===app01.models.Article,因此可以做相应的增删改查 re_path('app01/article',[ re_path('app01/article/delete/(\d+)',self.test)..... re_path('app01/blog/delete/(\d+)'.self.test1)..... re_path('app02/A/delete/(\d+)',self.test).... ],None,None) 此时的self指的就是传进来的表名对应 的实例化对象
路由分发步骤
第一步在组件app中声明django启动时,就执行Xadmin相关的方法和模块
from django.apps import AppConfig from django.utils.module_loading import autodiscover_modules class XadminConfig(AppConfig): name = 'Xadmin' def ready(self): autodiscover_modules('XXadmin')
第二步在Xadmin中设计相关函数
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.urls import path,re_path,include from django.shortcuts import HttpResponse,render class ModelXadmin(object): def __init__(self,model,site): self.model=model self.site=site @property def url(self): # self指调用他的对象,也就是site调用 url = [] url.append(re_path('^add/$',self.test)) url.append(re_path('^delete/(\d+)',self.test)) url.append(re_path('^update/(\d+)',self.test)) url.append(re_path('^check/(\d+)',self.test)) url.append(re_path('^\w+/$',self.test)) return url,None,None # [re_path('^delete/(\d+)',test),],None,None def test(self, request, *args): print(self.model) data_list=self.model.objects.all() print(data_list) return render(request, "XXadmin/XXadmin_check.html",{"data_list":data_list}) class XadminSite(object): def __init__(self): self._registry={} def get_url(self): # 对所有的表生成相应的路径 这是url调用的,因此此时的self就和url中self是一样的 url = [] for model, wait_class in self._registry.items(): # Xadmin.site.register(Blog)--->self._registry[model]=admin_class(model,self) ={blog:ModelXadmin(blog,site)} app_name = model._meta.app_label table_name = model._meta.model_name url_base = re_path('^{0}/{1}/'.format(app_name,table_name),wait_class.url()) # 假如是blog注册 re_path('app01/blog',ModelXadmin(Blog,site)) # 用配置类分发路径,这样我就可以拿到配置类内的所有方法,包括 re_path('app01/article',ModelXadmin(Article,site)) url.append(url_base) return url # [app01/article/,[re_path('^delete/(\d+)',test),],None,None] @property # 把该函数当成静态属性,可以通过 对象.urls调用,也就是在路由分发的时候这个函数就已经执行了 def urls(self): return self.get_url(), None, None # [app01/article/,[re_path('^delete/(\d+)',test),],None,None],None,None # 这个self是site调用这个方法,因此这个self指的是site,谁调用方法,方法里面的self就是该对象 def register(self,model,admin_class=None,**option): if not admin_class: admin_class=ModelXadmin self._registry[model]=admin_class(model,self) # z注意这里需要传值,即把需要的值放在init里面, model指的注册时传进来的表名 site=XadminSite() # Xadmin.site.urls # app01/article/add/1 # 那个对象调用方法 # 路径在django启动的时候就生成的,但是匹配却是一层一层往上找的 # 加入
第三步在url中调用方法,进行路径分发,注意路径匹配的第二个参数必须是一个变量名,而不是函数执行否则报错
path('Xadmin/', Xadmin.site.urls),
静态方法装饰器@property
@property修饰类内的方法就相当于声明我这个类方法可以通过取属性的方法即通过以下方法调用函数
class AdminSite(object): def __init__(self) self._registry={} # 这里用下划线是为了区分函数和变量名 @property # 对所有的表生成相应的路径 这是url调用的,因此此时的self就和url中self是一样的 def urls(self): return self.get_url(), None, None site=XadminSite() site.urls # 这样就可以调用函数了 site.urls ="name" # 可以通过等号传参数
正是因为这样就会出现,函数名与__init__里面同名时self.urls=name,左边的代码就相当于执行了函数,这就会报以下错误,或者外边调用site.urls时,不知调用谁.因此registry函数封装的数据用_registry进行命名.
AttributeError: can’t set attribute ,
再以学生的成绩为例,
class Student(object): def __init__(self, name, score): self.name = name self.__score = score @property def score(self): return self.__score @score.setter def score(self, score): if score < 0 or score > 100: raise ValueError('invalid score') self.__score = score s = Student('Bob', 59) s.score = 60 print (s.score) 结果是 60 s.score = 1000 结果是 ValueError: invalid score
当只有@property修饰函数时,函数只可读,不可以修改,如果想要修改,则需要通过用setter再次定义函数,两者相结合可以有效判断输入的数据是否合法.但也要注意,命名避免重复,否则会出现无限调用函数,即递归情形.变量名不合法
FBV实现思路
第一步把以表名都添加到列表当中,但是这种方法不知道,调用谁.
url路径分发进阶版
思路图如下
细节补充
以下主要参考 https://www.cnblogs.com/ParisGabriel/p/9302634.html
函数传参问题
函数的缺省参数: 语法: def 函数名 (形参名1=默认实参1, 形参2=默认实参2) 语句块 说明: 缺省参数必须从右至左依次存在的,如果一个参数有缺省参数, 则右侧的所有参数都必须有缺省参数 缺省参数可以通过关键字形式传参 def dog(name="Lc",flog=True): pass dog("娜娜",False) # 位置传参 dog(flog=False) # 关键字传参
其他参数类型,(了解即可)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
位置形参: 语法: def 函数名(形参1, 形参2.......) 语句块 元组形参: 语法: def 函数名(*元组形参名): 语句块 作用: 收集多余的位置传参 命名关键字形参: 语法: def 函数名(*, 命名关键字形参): 语句块 或 def 函数名(*args, 命名关键字形参): 语句块 (关键字形参 必须用关键字传参) 作用: 强制所有的参数都参数都必须用关键字传参或字典关键字传参 双星号字典传参: 语法: def 函数名(**字典形参名): 语句块 作用: 收集多余关键字传参 字典形参名通常命名为:kwargs 函数的参数说明: 位置形参、星号元组形参、命名关键字形参、双星号字典形参可以混合使用 函数自左到右的顺序为: 1.位置形参 2.星号元组形参 3.命名关键字形参 4.双星号字典形参
_meta方法补充(类表方法)
Python有反射机制,Django也不例外,也有很好的反射机制,每个Django模型都有一个属性_meta,_meta也有属性和方法,这些属性和方法反射出了模型的一些特性,
在django中_meta方法,内置有很多方法,有以下方法
_meta的属性和方法 '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_field_cache',
'_field_name_cache', '_fields', '_fill_fields_cache', '_fill_m2m_cache', '_fill_related_many_to_many_cache',
'_fill_related_objects_cache', '_join_cache', '_m2m_cache', '_many_to_many', '_name_map', '_prepare',
'_related_many_to_many_cache', '_related_objects_cache', '_related_objects_proxy_cache',
'abstract', 'abstract_managers', 'add_field', 'add_virtual_field', 'admin', 'app_label',
'auto_created', 'auto_field', 'concrete_managers', 'concrete_model', 'contribute_to_class',
'db_table', 'db_tablespace', 'duplicate_targets', 'fields', 'get_add_permission', 'get_all_field_names',
'get_all_related_m2m_objects_with_model', 'get_all_related_many_to_many_objects', 'get_all_related_objects',
'get_all_related_objects_with_model', 'get_ancestor_link', 'get_base_chain', 'get_change_permission',
'get_delete_permission', 'get_field', 'get_field_by_name', 'get_fields_with_model', 'get_latest_by',
'get_m2m_with_model', 'get_ordered_objects', 'get_parent_list', 'has_auto_field', 'init_name_map',
'installed', 'local_fields', 'local_many_to_many', 'managed', 'many_to_many', 'module_name', 'object_name',
'order_with_respect_to', 'ordering', 'parents', 'permissions', 'pk', 'pk_index', 'proxy', 'proxy_for_model',
'related_fkey_lookups', 'setup_pk', 'setup_proxy', 'unique_together', 'verbose_name', 'verbose_name_plural',
'verbose_name_raw', 'virtual_fields'
1 User._meta.get_field
(field_name),field是字符串,即可以通过字符串查到表对应字段对象,包括外键,但是要通过related_name进行查找.
注意 如果没有找到具有给定名称的字段, FieldDoesNotExist
则会引发异常
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
>>> from django.contrib.auth.models import User # A field on the model >>> User._meta.get_field('username') <django.db.models.fields.CharField: username> # A field from another model that has a relation with the current model >>> User._meta.get_field('logentry') <ManyToOneRel: admin.logentry> # A non existent field >>> User._meta.get_field('does_not_exist') Traceback (most recent call last): ... FieldDoesNotExist: User has no field named 'does_not_exist'
得到某个字段对象后,就可以拿到相关的参数,如拿到字段 中文名,在页面布局的时候会用到
self.model._meta.get_field(field).verbose_name # verbose_name在admin中会用到
2 检索模型当中所有字段User._meta.get_fields()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
>>> from django.contrib.auth.models import User >>> User._meta.get_fields() (<ManyToOneRel: admin.logentry>, <django.db.models.fields.AutoField: id>, <django.db.models.fields.CharField: password>, <django.db.models.fields.DateTimeField: last_login>, <django.db.models.fields.BooleanField: is_superuser>, <django.db.models.fields.CharField: username>, <django.db.models.fields.CharField: first_name>, <django.db.models.fields.CharField: last_name>, <django.db.models.fields.EmailField: email>, <django.db.models.fields.BooleanField: is_staff>, <django.db.models.fields.BooleanField: is_active>, <django.db.models.fields.DateTimeField: date_joined>, <django.db.models.fields.related.ManyToManyField: groups>, <django.db.models.fields.related.ManyToManyField: user_permissions>)
3 常用的方法
cls_name = model._meta.model_name #当前表映射类名称的小写
cls_name = modle._meta.object_name: #属性,模型名,字符串,返回自定义的类名原型. app_name = model._class._meta.app_label #当前表所在app的名称
model._meta.auto_field: 属性,返回所有自增字段类型的字段,一般是`id`字段,如<django.db.models.fields.AutoField: id> db_table:属性,该模型所用的数据表的名称,关于数据表的名称
4