CRM前情
1. django源码settings
1.1 settings源码
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" from django.conf import settings settings = LazySettings() class LazySettings(LazyObject): def _setup(self, name=None): """ Load the settings module pointed to by the environment variable. This is used the first time we need any settings at all, if the user has not previously configured the settings manually. """ # 从全局大字典os.environ中获取一个键为ENVIRONMENT_VARIABLE对应的值 settings_module = os.environ.get(ENVIRONMENT_VARIABLE) self._wrapped = Settings(settings_module) class Settings(object): def __init__(self, settings_module): # BBS.settings # update this dict from global settings (but only for ALL_CAPS settings) for setting in dir(global_settings): # 拿到global_settings文件里面所有的变量名 if setting.isupper(): # 配置文件中只能写大写的变量名 setattr(self, setting, getattr(global_settings, setting)) self.SETTINGS_MODULE = settings_module mod = importlib.import_module(self.SETTINGS_MODULE) # from BBS import settings for setting in dir(mod): # 获取暴露给用户settings配置中的变量名 if setting.isupper(): setting_value = getattr(mod, setting) setattr(self, setting, setting_value) # 利用字典的键存在与否 完成用户配置了用用户的,用户没配置用全局
1.2 动态导入模块
import importlib res = 'conf.settings' module = importlib.import_module(res) # 以字符串的形式导入模块 print(module) print(module.NAME) # 可以得到conf.settings下的NAME的值
1.3
# __init__.py: import importlib from lib.conf import global_settings import os class Settings(object): def __init__(self): for name in dir(global_settings): if name.isupper(): k = name v = getattr(global_settings, name) setattr(self, k, v) # 将项目默认的配置文件中所有的配置文件中所有的配置以键值对的形式存入到了settings对象中 # 从全局的大字典中回去暴露给用户的settings文件路径 module_path = os.environ.get('xxx') module = importlib.import_module(module_path) for name in dir(module): if name.isupper(): k = name v = getattr(module, name) setattr(self, k, v) # 将暴露给用户的配置文件中所有的配置文件中所有的配置以键值对的形式存入到了settings对象中 settings = Settings()
2. ORM复习
''' 只有queryset对象才能查看sql语句 print(models.Publish.objects.all().query) ''' """ add,remove,set:三个可以传一个或多个参数 并且即可以是数字也可以是对象 clear:不传参数 直接清空 """ # 外键字段的增删改查 ''' 创建create ''' # 传数字 models.Book.objects.create(title='三国演义', price='199', publish_id=1) # 传对象 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.create(title='水浒传',price='99', publish=publish_obj) ''' 修改update ''' # 传数字 models.Book.objects.filter(pk=1).update(publish_id=2) # 传对象 publish_obj = models.Publish.objects.filter(pk=1).first() models.Book.objects.filter(pk=1).update(publish=publish_obj) """ 增加add """ # add即可以传数字 也可以传对象 还支持传多个 单个单个的参数 不要传容器类型 # 传数字 book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.add(2) # 传对象 book_obj = models.Book.objects.filter(pk=2).first() author_obj = models.Author.objects.filter(pk=1).first() book_obj.authors.add(author_obj) # 传所有对象 book_obj = models.Book.objects.filter(pk=1).first() author_list = models.Author.objects.all() book_obj.authors.add(*author_list) """ 删除remove, clear """ # 传数字 在多对多表中删除书的id为1, 作者id为1, 2,3的数据 book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.remove(1) book_obj.authors.remove(2, 3) # 传对象 book_obj = models.Book.objects.filter(pk=2).first() author_obj = models.Author.objects.all() book_obj.authors.remove(*author_obj) # clear book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.clear() # 清空当前对象所对应的多对多关系 """ 修改set """ # 传数字 book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.set([3,]) # 设置Book 的id=1的字段的author的值为3 # 传对象 book_obj = models.Book.objects.filter(pk=1).first() author_list = models.Author.objects.all() book_obj.authors.set(author_list) # 设置author的所有对应Book的id=1
# 基于对象的跨表查询 (都是子查询) # 1.查询书籍是三国演义的出版社的名称 book_obj = models.Book.objects.filter(title='三国演义').first() print(book_obj.publish.name) # 2.查询北方出版社出版的所有的书 publish_obj = models.Publish.objects.filter(name='北方出版社').first() print(publish_obj.book_set) # app01.Book.None 当出现这个结果时,代表少了一个 all() print(publish_obj.book_set.all()) # 3.查询作者是jason的写过的所有的书 author_obj = models.Author.objects.filter(name='jason').first() print(author_obj.book_set.all()) # 4.查询作者jason的住址 author_obj = models.Author.objects.filter(name='jason').first() print(author_obj.author_detail.addr) # 5.查询手机号是111的作者姓名 author_detail = models.AuthorDetail.objects.filter(phone='111').first() print(author_detail.author.name)
# 基于双下划线的跨表查询 # 1.查询书籍是三国演义的出版社名称 res = models.Book.objects.filter(title='三国演义').values('publish__name') print(res) # 2.查询书籍是三国演义的作者姓名 res = models.Book.objects.filter(title='三国演义').values('authors__name') print(res) # 3.查询作者jason的手机号 res = models.Author.objects.filter(name='jason').values('author_detail__phone') print(res) # 4.查询书籍是三国演义的作者的手机号 res = models.Book.objects.filter(title='三国演义').values('authors__author_detail__phone') print(res) # 反向查询 # 1.查询出版社为北方出版社的所有图书的名字和价格 res = models.Publish.objects.filter(name='北方出版社').values('book__title', 'book__price') print(res) # 2.查询作者姓名是jason的手机号 res = models.AuthorDetail.objects.filter(author__name='jason').values('phone') print(res)
3. django admin后台管理使用详细
3.1 表的注册
admin.site.register(models.Book,BookConfig)
admin.site.register(models.Publish)
admin.site.register(models.Author)
admin.site.register(models.AuthorDetail)
3.2 增删改查的url
http://127.0.0.1:8000/admin/app01/book/ book表的查看http://127.0.0.1:8000/admin/app01/book/add/ book表的添加http://127.0.0.1:8000/admin/app01/book/3/change/ book表的编辑http://127.0.0.1:8000/admin/app01/book/3/delete/ book表的删除页面 http://127.0.0.1:8000/admin/app01/publish/ publish表的查看http://127.0.0.1:8000/admin/app01/publish/add/ publish表的添加http://127.0.0.1:8000/admin/app01/publish/3/change/ publish表的编辑http://127.0.0.1:8000/admin/app01/publish/3/delete/ publish表的删除页面
3.3 五大常用方法
list_display
list_play_links
search_fields
list_filter
actions
3.3.1
list_display = ['title', 'price', 'publish_date', 'publish']
list_display_links = ['title','price']
search_fields = ['title', 'price']
def patch_init(self, request, queryset): queryset.update(price=666) patch_init.short_description = '价格批量修改' actions = [patch_init]
4. django admin 启动源码
4.1 启动源码
django在启动的时候会依次执行每一个应用下的admin.py文件
from django.contrib import admin INSTALLED_APPS = [ 'django.contrib.admin',] from django.utils.module_loading import autodiscover_modules def autodiscover(): autodiscover_modules('admin', register_to=site)
4.2 注册源码
admin.site.register(models.Publish) # 仅仅是将注册了的模型表和以模型表为 # 参数实例化产生的对象当做键值对存入了site对象中的_registry字段 class AdminSite(object): def __init__(self, name='admin'): self._registry = {} # model_class class -> admin_class instance def register(self, model_or_iterable, admin_class=None, **options): if not admin_class: admin_class = ModelAdmin # Instantiate the admin class to save in the registry self._registry[model] = admin_class(model) site = AdminSite() @python_2_unicode_compatible class ModelAdmin(BaseModelAdmin): # 配置类 list_display = ('__str__',) list_display_links = () list_filter = () ...
5. 实现单例模式
1.基于classmethod 2.基于装饰器 3.基于元类__call__ 4.基于__new__ 5.基于模块
5.1 基于classmethod
class Mysql(object): _instance = None def __init__(self, host, port): self.host = host self.port = port @classmethod def singleton(cls): if not cls._instance: cls._instance = cls('127.0.0.1', 8080) return cls._instance obj1 = Mysql.singleton() obj2 = Mysql.singleton() obj3 = Mysql('192.168.11.11', 8080) print(id(obj1), id(obj2), id(obj3)) # 1610636363200 1610636363200 1610636363256
5.2 基于装饰器
def singleton(cls): _instance = cls('127.0.0.1', 8080) def inner(*args, **kwargs): if args or kwargs: obj = cls(*args, **kwargs) return obj return _instance return inner @singleton class Mysql(object): def __init__(self, host, port): self.host = host self.port = port obj1 = Mysql() obj2 = Mysql() obj3 = Mysql('127.0..0', 8080) print(id(obj1), id(obj2), id(obj3)) # 2382258537976 2382258537976 2382258540104
5.3 基于元类__call__
class MymetClass(type): def __call__(self, *args, **kwargs): if not getattr(self, '_instance'): self._instance = super().__call__(*args, **kwargs) return self._instance class Mysql(object, metaclass=MymetClass): _instance = None def __init__(self, host, port): self.host = host self.port = port obj1 = Mysql('127.0.0.1', 8080) obj2 = Mysql('127.0.0.1', 8000) print(id(obj1), id(obj2)) # 2501473371584 2501473371584
5.4 基于__new__
class Mysql(object): _instance = None def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = object.__new__(cls) return cls._instance obj1 = Mysql('jason') obj2 = Mysql('egon') print(id(obj1), id(obj2)) # 1883165918712 1883165918712 print(obj1.name) # egon print(obj2.name) # egon
5.5 基于模块
# singleton1.py class Settings(object): pass settings = Settings() from singleton1 import settings print(id(settings)) # 2385839183744 from singleton1 import settings print(id(settings)) # 2385839183744 # singleton2.py from singleton1 import settings def func(): print(id(settings)) from singleton1 import settings from singleton2 import func print(id(settings)) # 2479206335600 func() # 2479206335600
6. 路由分发的本质
6.1 路由分发的本质
url(r'^test/', ([], None, None)) # 中括号中可以继续Wie路由,这样可以无穷尽的路由
6.2 django admin中的路由源码
url(r'^admin/', admin.site.urls), # urls看似为一个属性,实则为一个方法, 点击urls结果如下 @property def urls(self): return self.get_urls(), 'admin', self.name # 点击get_urls(), 结果如下 def get_urls(self): urlpatterns = [ url(r'^$', wrap(self.index), name='index'), url(r'^login/$', self.login, name='login'), url(r'^logout/$', wrap(self.logout), name='logout'), url(r'^password_change/$', wrap(self.password_change, cacheable=True), name='password_change'), url(r'^password_change/done/$', wrap(self.password_change_done, cacheable=True), name='password_change_done'), url(r'^jsi18n/$', wrap(self.i18n_javascript, cacheable=True), name='jsi18n'), url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$', wrap(contenttype_views.shortcut), name='view_on_site'), ] return urlpatterns # 由上可以推论出路由分发的本质 第一位元组内的第一个值一定为一个列表
6.3 一级路由与二级路由
url(r'^index/', ([ url(r'^test1/',([ url(r'^test1_1', test1_1), url(r'^test1_2', test1_2), url(r'^test1_3', test1_3), ],None, None)), url(r'^test2/', test2), ], None, None))