python 全栈开发,Day116(可迭代对象,type创建动态类,偏函数,面向对象的封装,获取外键数据,组合搜索,领域驱动设计(DDD))...
?
昨日內(nèi)容回顧
1. 三個(gè)類 ChangeList,封裝列表頁面需要的所有數(shù)據(jù)。StarkConfig,生成URL和視圖對應(yīng)關(guān)系 + 默認(rèn)配置 AdminSite,用于保存 數(shù)據(jù)庫類 和 處理該類的對象 的對應(yīng)關(guān)系 + 路由分發(fā)_registry = {} 2. 知識(shí)點(diǎn) inclusion_tagyieldurlencode_meta.model_name_meta.app_label深淺拷貝 QueryDict對象默認(rèn)不可改 _mutable=True 生成器 路由分發(fā):- include- ([],None,None)函數(shù)和方法的區(qū)別?Q的作用?構(gòu)造復(fù)雜的查詢條件models.User.object.filter(name__contains='李')models.User.object.filter(name__contains='李',email__contains='李')構(gòu)造 or c1 = Q()c1.connector = 'OR'c1.children.append( ('name__contains','李') )c1.children.append( ('email__contains','李') )c2 = Q()c2.connector = 'ADN'c2.children.append( ('id__gt',2) )c3.children.append( ('age__lte',5) )c3 = Q()c3.connector = 'ADN'c3.add(c1,"ADN")c3.add(c2,"ADN")等同于(name=li or email = li) AND ( id>2 and age<=5)models.User.object.filter(con)反射 有2個(gè)地方用到了反射list_display: # 顯示指定的列 row.name getattr(row,'name')# 批量操作response = getattr(self, action_name)(request)pass繼承 class RoleConfig(StarkConfig):pass self到底是誰?反向生成URLreverse('xxx')reverse('namespace:xxx')多個(gè)namespace,也是以冒號(hào)分隔分頁(保留原搜索條件) 跳轉(zhuǎn)的url中保留_filter=原搜索條件ModelForm組件添加和修改functools- wraps,用于保留原函數(shù)的元信息(函數(shù)名/函數(shù)注釋等信息)- partial,偏函數(shù)為函數(shù)默認(rèn)傳參。import functoolsdef func(a1,a2):print(a1+a2)new_func = functools.partial(func,8)new_func(7)new_func(2)new_func(8)預(yù)留可擴(kuò)展位置request.GETrequest.GET.get('x')request.GET['x']request.GET.getlist('xxx')request.GET._mutable = True request.GET.copy()request.GET.urlencode()mark_safe xss攻擊是什么?跨站腳本攻擊一般用js代碼,進(jìn)行攻擊。獲取cookie,模擬登錄,做非法操作!單例模式- 多個(gè)模塊之間導(dǎo)入- 共享同一個(gè)數(shù)據(jù)時(shí)獲取函數(shù)名__name__autodiscover_module自動(dòng)發(fā)現(xiàn)模塊裝飾器 添加request參數(shù),方便非視圖函數(shù)調(diào)用requestorder_by排序展示__str__在models.py中使用3. QueryDict對象 params = request.GET.copy() # 使用深copyparams._mutable = True # 允許修改 params['k1'] = 'v1' # 添加單個(gè)params.setlist('k2',[11,22]) # 添加多個(gè) View Code?
一、可迭代對象
什么是可迭代對象
在之前學(xué)過的容器中,許多容器都是可迭代對象,可以直接用于for…in…循環(huán)的而對象都是可迭代對象,比如:list,tuple,dict,set,str等等。
可迭代對象滿足條件:實(shí)現(xiàn)了__iter__方法
?
注意:__iter__方法必須返回一個(gè)迭代器(iter)
?
可迭代對象并不是一種具體的數(shù)據(jù)類型,比如list是可迭代對象,dict也是可迭代對象。
如何判斷一個(gè)對象是否是可迭代對象? 使用isinstance()函數(shù)
from collections import Iterablea = isinstance("123",Iterable) b = isinstance(1,Iterable) print(a) #字符串是不是可迭代對象 返回True print(b) #數(shù)字是不是可迭代對象 返回False?
舉例1
看下面一段代碼
class Foo(object):passobj = Foo() for item in obj:print(item)執(zhí)行報(bào)錯(cuò):
TypeError: 'Foo' object is not iterable提示不可迭代,怎么讓它可以迭代?
先來看可迭代對象滿足條件:實(shí)現(xiàn)了__iter__方法
?
那么在類中,定義一個(gè)__iter__方法,返回迭代器就可以了!
class Foo(object):def __iter__(self):# return iter([11,22,33,44]) # 返回迭代器yield 11 # 返回生成器(迭代器的一種)obj = Foo() for item in obj:print(item)執(zhí)行輸出: 11
?
舉例2
這是汽車之家的篩選頁面,每一個(gè)行的數(shù)據(jù)是循環(huán)展示的!如何構(gòu)造這些數(shù)據(jù)?
方法一:使用字典
data_list= [['1.0以下','1.1-1.6'],['汽油','柴油','混合動(dòng)力','電動(dòng)'], ]for row in data_list:for field in row:print(field)執(zhí)行輸出:
1.0以下 1.1-1.6 汽油 柴油 混合動(dòng)力 電動(dòng) View Code?
方法二:使用對象+yield
class Row(object):def __init__(self,data):self.data = datadef __iter__(self):for item in self.data:yield itemdata_list= [Row(['1.0以下','1.1-1.6']),Row(['汽油','柴油','混合動(dòng)力','電動(dòng)']), ]for row in data_list:for field in row:print(field) View Code執(zhí)行輸出,效果同上!
?
為什么要用對象構(gòu)造數(shù)據(jù)?因?yàn)橐獦?gòu)造更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)!
class Row(object):def __init__(self,data):self.data = datadef __iter__(self):yield "<div>"yield '全部'for item in self.data:yield "<a href='/index/?p1=1.0'>%s</a>" %itemyield "</div>"data_list= [Row(['1.0以下','1.1-1.6']),Row(['汽油','柴油','混合動(dòng)力','電動(dòng)']), ]for row in data_list:for field in row:print(field) View Code執(zhí)行輸出:
<div> 全部 <a href='/index/?p1=1.0'>1.0以下</a> <a href='/index/?p1=1.0'>1.1-1.6</a> </div> <div> 全部 <a href='/index/?p1=1.0'>汽油</a> <a href='/index/?p1=1.0'>柴油</a> <a href='/index/?p1=1.0'>混合動(dòng)力</a> <a href='/index/?p1=1.0'>電動(dòng)</a> </div> View Code可以看出,這段數(shù)據(jù),比上面的復(fù)雜!
如果用列表,那么有很多if判斷!使用類,2層for循環(huán)就出來了!
為什么要輸出a標(biāo)簽?因?yàn)榍岸虽秩韭闊?#xff0c;后端生成a標(biāo)簽。前端容易展示,還可以做一些復(fù)雜的需求!
?
二、type創(chuàng)建動(dòng)態(tài)類
前戲
舉例1
def gen_cls():class Foo(object):passreturn Foocls = gen_cls()print(cls) View Code執(zhí)行輸出:
<class '__main__.gen_cls.<locals>.Foo'>對象是由類創(chuàng)建的。那么類是由誰創(chuàng)建的?先帶著這個(gè)疑問
舉例2
name = "Foo" country = "中國" detail = lambda self, x: x + 1根據(jù)以上三個(gè)參數(shù)創(chuàng)建一個(gè)類,類中有兩個(gè)成員。實(shí)現(xiàn)的效果如下:
class Foo(object):country = '中國'def detail(self,x):return x + 1如何用代碼實(shí)現(xiàn)呢?
不能這么寫
class name(object):country = '中國'...那么class名就是name了,需要使用type
?
type創(chuàng)建動(dòng)態(tài)類
type還有一種完全不同的功能,動(dòng)態(tài)的創(chuàng)建類。
type可以接受一個(gè)類的描述作為參數(shù),然后返回一個(gè)類。(要知道,根據(jù)傳入?yún)?shù)的不同,同一個(gè)函數(shù)擁有兩種完全不同的用法是一件很傻的事情,但這在Python中是為了保持向后兼容性)
?
type可以像這樣工作:
type(類名,由父類名稱組成的元組(針對繼承的情況,可以為空),包含屬性的字典(名稱和值))?
根據(jù)上面的3個(gè)條件,使用type創(chuàng)建一個(gè)類
name = "Foo" country = "中國" detail = lambda self, x: x + 1 # 使用type創(chuàng)建動(dòng)態(tài)類 cls = type(name, (object,), {'country': '中國', 'detail': lambda self, x: x + 1})obj = cls() print(obj) print(obj.country) print(obj.detail(100)) View Code執(zhí)行輸出:
<__main__.Foo object at 0x000001E0FBF2DA20> 中國 101根據(jù)條件,由type動(dòng)態(tài)創(chuàng)建了一個(gè)類。類的基本操作,比如實(shí)例化,獲取靜態(tài)字段,傳參,都沒有問題!
?
函數(shù)type實(shí)際上是一個(gè)元類。type就是Python在背后用來創(chuàng)建所有類的元類。type就是Python的內(nèi)建元類
總結(jié):對象是由類創(chuàng)建的。那么類默認(rèn)是由type創(chuàng)建的
?
三、偏函數(shù)
什么是偏函數(shù)
偏函數(shù)是2.5版本以后引進(jìn)來的東西。屬于函數(shù)式編程的一部分,使用偏函數(shù)可以通過有效地"凍結(jié)"那些預(yù)先確定的參數(shù),來緩存函數(shù)參數(shù),然后在運(yùn)行時(shí),當(dāng)獲得需要的剩余參數(shù)后,可以將他們解凍,傳遞到最終的參數(shù)中,從而使用最終確定的所有參數(shù)去調(diào)用函數(shù)。
舉例
示例函數(shù)
def func(a1,a2):return a1+a2res = func(1,3) print(res)執(zhí)行輸出:4
使用偏函數(shù)
import functools def func(a1,a2):return a1+a2# 相當(dāng)于給第一個(gè)參數(shù),設(shè)置默認(rèn)參數(shù)8 new_func = functools.partial(func,8) # 傳入第二個(gè)參數(shù) res = new_func(7) print(res)執(zhí)行輸出:15
?
func有2個(gè)參數(shù),怎么確定是給第一個(gè)參數(shù),設(shè)置了默認(rèn)參數(shù)?
import functools def func(a1,a2=22):return a1+a2# 相當(dāng)于給第一個(gè)參數(shù),設(shè)置默認(rèn)參數(shù)8 new_func = functools.partial(func,8) # 傳入第二個(gè)參數(shù) res = new_func(7) print(res)執(zhí)行輸出:15
注意:a1直接設(shè)置默認(rèn)參數(shù),是會(huì)報(bào)錯(cuò)的!默認(rèn)參數(shù)必須在位置參數(shù)的后面!
在flask中,會(huì)用到偏函數(shù)
?
四、面向?qū)ο蟮姆庋b
看下面一段數(shù)據(jù)
list_filter = ['全智賢','高圓圓','胡歌',]如何用代碼區(qū)分性別?
?
第一種方法:使用字典
list_filter = [{'name':'全智賢','sex':'女'},{'name':'高圓圓','sex':'女'},{'name':'胡歌','sex':'男'}, ]再區(qū)分衣服的顏色呢?
list_filter = [{'name':'全智賢','sex':'女','color':'pink'},{'name':'高圓圓','sex':'女','color':'red'},{'name':'胡歌','sex':'男','color':'black'}, ]如果還有其它屬性呢?繼續(xù)加?
使用字典也是一個(gè)封裝思想
?
第二種方法:使用類(推薦)
class Option(object):def __init__(self,name,sex,color):self.name = nameself.sex = sexself.color = colorlist_filter = [# 字典對象做封裝Option(name='全智賢',sex='女',color = 'pink'),Option(name='高圓圓',sex='女',color = 'red'),Option(name='胡歌',sex='男',color = 'black'), ]for item in list_filter:print(item.__dict__) View Code執(zhí)行輸出:
{'name': '全智賢', 'color': 'pink', 'sex': '女'} {'name': '高圓圓', 'color': 'red', 'sex': '女'} {'name': '胡歌', 'color': 'black', 'sex': '男'}通過這2種方法對比,使用類更好一點(diǎn)!
如果使用字典,那么第一條數(shù)據(jù),加了一個(gè)參數(shù)。而另外2條數(shù)據(jù),卻沒有加!
那么頁面展示就會(huì)錯(cuò)亂!
而使用類,則不會(huì)這個(gè)情況!另外一點(diǎn),使用類,可以構(gòu)造更加復(fù)雜的數(shù)據(jù)結(jié)構(gòu)!
使用類,是新的 封裝思想。可擴(kuò)展功能比較方便
?
五、獲取外鍵數(shù)據(jù)
外鍵分為3種:?FK/M2M/O2O,分別對應(yīng)一對多,多對多,一對一
給定2個(gè)參數(shù)
model_class = Depart # 模型表類 _field = "user" # 外鍵字段要獲取外鍵字段對應(yīng)的所有數(shù)據(jù),如何獲取?
?
新建項(xiàng)目untitled4,注意:django版本為1.11
?
修改models.py,新建2個(gè)表
from django.db import models# Create your models here. class UserInfo(models.Model):title = models.CharField(verbose_name='標(biāo)題',max_length=32)def __str__(self):return self.titleclass Depart(models.Model):name = models.CharField(verbose_name='部門名稱',max_length=32)tel = models.CharField(verbose_name='聯(lián)系電話',max_length=32)user = models.ForeignKey(verbose_name='負(fù)責(zé)人',to='UserInfo')def __str__(self):return self.name View Code使用2個(gè)命令生成表
python manage.py makemigrations python manage.py migrate?
增加數(shù)據(jù),使用Navicat打開sqlite3數(shù)據(jù)庫,執(zhí)行sql語句
INSERT INTO "app01_depart" ("name", "tel", "user_id") VALUES ('總經(jīng)理', 23456342, 1); INSERT INTO "app01_depart" ("name", "tel", "user_id") VALUES ('技術(shù)部', 34565422, 1); INSERT INTO "app01_depart" ("name", "tel", "user_id") VALUES ('運(yùn)營部', 34344523, 2);INSERT INTO "app01_userinfo" ("title") VALUES ('xiao'); INSERT INTO "app01_userinfo" ("title") VALUES ('zhang'); View Code?
修改urls.py,增加路徑
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [url(r'^admin/', admin.site.urls),url(r'^index/', views.index), ] View Code?
修改views.py,增加視圖函數(shù)
from django.shortcuts import render,HttpResponse from app01 import models # Create your views here. def index(request):# 外鍵對象,通過get_field獲取fk_obj = models.Depart._meta.get_field("user")print(fk_obj,type(fk_obj))# .all表示獲取所有數(shù)據(jù)user_info_queryset = fk_obj.rel.model.objects.all()print(user_info_queryset)for i in user_info_queryset:print('row:',i) # 打印每一個(gè)行的數(shù)據(jù)return HttpResponse('...') View Code啟動(dòng)django項(xiàng)目,訪問首頁
查看Pycharm控制臺(tái)輸出:
app01.Depart.user <class 'django.db.models.fields.related.ForeignKey'> <QuerySet [<UserInfo: xiao>, <UserInfo: zhang>]> row: xiao row: zhang注意:FK/M2M/O2O都是通過get_field來獲取的
?
六、組合搜索
展示頁面
務(wù)必下載github代碼:
https://github.com/987334176/luffy_stark/archive/v1.2.zip
因?yàn)橄旅娴膬?nèi)容,都是這份代碼來修改的!
?
修改?stark-->templates-->stark-->changelist.html
{% extends 'stark/layout.html' %} {% load stark %}{% block css %}<style>.comb-search {padding: 5px 20px;}.comb-search .row .whole {width: 60px;float: left;}.comb-search .row .others {padding-left: 60px;}.comb-search .row a {display: inline-block;padding: 5px 8px;margin: 3px;border: 1px solid #d4d4d4; }.comb-search .row a {display: inline-block;padding: 5px 8px;margin: 3px;border: 1px solid #d4d4d4; }.comb-search a.active {color: #fff;background-color: #337ab7;border-color: #2e6da4; }</style> {% endblock %} {% block content %}<div>{#組合搜索#}<div class="comb-search"><div class="row"><div class="whole"><a href="#">全部</a></div><div class="others"><a href="#">條件1</a><a href="#">條件2</a><a href="#">條件3</a></div></div></div>{#添加按鈕#}{% if cl.add_btn %}<div style="margin: 5px 0;">{{ cl.add_btn }}</div>{% endif %}{#搜索框#}{% if cl.search_list %}<div style="float: right;"><form method="GET" class="form-inline"><div class="form-group"><input class="form-control" type="text" name="q" value="{{ cl.q }}" placeholder="關(guān)鍵字搜索"><button class="btn btn-primary" type="submit"><i class="fa fa-search" aria-hidden="true"></i></button></div></form></div>{% endif %}<form class="form-inline" method="post">{% csrf_token %}{#批量操作#}{% if cl.action_list %}<div class="form-group"><select name="action" class="form-control" style="min-width: 200px;"><option>請選擇功能</option>{% for item in cl.action_list %}<option value="{{ item.name }}">{{ item.text }}</option>{% endfor %}</select><input class="btn btn-primary" type="submit" value="執(zhí)行"></div>{% endif %}{#使用table展示數(shù)據(jù)#}{% table cl %}{#分頁展示#}<nav aria-label="Page navigation"><ul class="pagination">{{ cl.page.page_html|safe }}</ul></nav></form></div>{% endblock %} View Code訪問url:?http://127.0.0.1:8000/stark/app01/depart/list/
效果如下:
?
修改 stark-->server-->stark.py,增加變量 list_filter,增加一個(gè)鉤子函數(shù)?get_list_filter
使用get_field獲取字段
import functools from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect from types import FunctionType from django.utils.safestring import mark_safe from django.urls import reverse from django import forms from django.db.models import Q from django.http import QueryDictclass ChangeList(object):"""封裝列表頁面需要的所有功能"""def __init__(self,config,queryset,q,search_list,page):### 處理搜索 ###self.q = q # 搜索條件self.search_list = search_list # 搜索字段self.page = page # 分頁# 配置參數(shù)self.config = config# 批量操作self.action_list = [{'name': func.__name__, 'text': func.text} for func in config.get_action_list()]# 添加按鈕self.add_btn = config.get_add_btn()# ORM執(zhí)行結(jié)果self.queryset = queryset# 顯示的列self.list_display = config.get_list_display()class StarkConfig(object):def __init__(self,model_class,site):self.model_class = model_classself.site = site# 定義request變量,用于非視圖函數(shù)使用。# 在wrapper裝飾器中,對這個(gè)值重新賦值!self.request = None# url中的搜索條件,存在字典中。key為_filterself.back_condition_key = "_filter"def display_checkbox(self,row=None,header=False): # 顯示復(fù)選框if header:# 輸出中文return "選擇"# 注意:這里要寫row.pk,不能寫row.id。你不能保證每一個(gè)表的主鍵都是idreturn mark_safe("<input type='checkbox' name='pk' value='%s' />" % row.pk)def display_edit(self, row=None, header=False):if header:return "編輯"return mark_safe('<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))def display_del(self, row=None, header=False):if header:return "刪除"return mark_safe('<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))def display_edit_del(self, row=None, header=False):if header:return "操作"tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>""" % (self.reverse_edit_url(row), self.reverse_del_url(row),)return mark_safe(tpl)def multi_delete(self, request): # 批量刪除"""批量刪除的action:param request::return:"""pk_list = request.POST.getlist('pk')self.model_class.objects.filter(pk__in=pk_list).delete()# return HttpResponse('刪除成功') multi_delete.text = "批量刪除" # 添加自定義屬性textdef multi_init(self,request): # 批量初始化print('批量初始化')multi_init.text = "批量初始化" # 添加自定義屬性text order_by = [] # 需要排序的字段,由用戶自定義list_display = [] # 定義顯示的列,由用戶自定義model_form_class = None # form組件需要的model_classaction_list = [] # 批量操作方法# 搜索字段,如果是跨表字段,要按照ORM語法來search_list = []list_filter = [] # 組合搜索def get_order_by(self): # 獲取排序列表return self.order_bydef get_list_display(self): # 獲取顯示的列return self.list_displaydef get_add_btn(self): # 顯示添加按鈕return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())def get_model_form_class(self):"""獲取ModelForm類:return:"""if self.model_form_class:return self.model_form_classclass AddModelForm(forms.ModelForm):class Meta:model = self.model_classfields = "__all__"return AddModelFormdef get_action_list(self): # 獲取批量操作方法val = [] # 空列表# 擴(kuò)展列表的元素 val.extend(self.action_list)return valdef get_action_dict(self): # 獲取匹配操作字典val = {}for item in self.action_list:# 以方法名為keyval[item.__name__] = itemreturn valdef get_search_list(self): # 獲取搜索字段val = []val.extend(self.search_list)return valdef get_search_condition(self, request): # 根據(jù)關(guān)鍵字,組合ORM查詢語句search_list = self.get_search_list() # ['name','tel']q = request.GET.get('q', "") # 搜索條件con = Q()con.connector = "OR" # 以O(shè)R作為連接符if q: # 判斷條件不為空for field in search_list:# 合并條件進(jìn)行查詢, __contains表示使用like查詢con.children.append(('%s__contains' % field, q))return search_list, q, condef get_list_filter(self): # 獲取組合搜索條件val = []val.extend(self.list_filter)return valdef changelist_view(self, request):"""所有URL查看列表頁面:param request::return:"""if request.method == 'POST':action_name = request.POST.get('action')action_dict = self.get_action_dict()if action_name not in action_dict:return HttpResponse('非法請求')response = getattr(self, action_name)(request)if response:return response### 處理搜索 ###search_list, q, con = self.get_search_condition(request)# ##### 處理分頁 #####from stark.utils.pagination import Pagination# 總條數(shù)total_count = self.model_class.objects.filter(con).count()# 復(fù)制GET參數(shù)query_params = request.GET.copy()# 允許編輯query_params._mutable = True# 使用分頁類Pagination,傳入?yún)?shù)。每頁顯示3條page = Pagination(request.GET.get('page'), total_count, request.path_info, query_params, per_page=3)# 根據(jù)排序列表進(jìn)行排序,以及分頁功能queryset = self.model_class.objects.filter(con).order_by(*self.get_order_by())[page.start:page.end]cl = ChangeList(self, queryset, q, search_list, page)# ######## 組合搜索 ########## list_filter = ['name','user']list_filter = self.get_list_filter()for field in list_filter:# 如果field = "name" --> 查Depart所有數(shù)據(jù)# 如果field = "user" --> 查UserInfo所有數(shù)據(jù)_field = self.model_class._meta.get_field(field)print(_field,type(_field)) # 打印字段類型 context = {'cl': cl}# 注意:要傳入?yún)?shù)return render(request,'stark/changelist.html',context)def add_view(self, request):"""所有的添加頁面,都在此方法處理使用ModelForm實(shí)現(xiàn):param request::return:"""# 添加數(shù)據(jù),使用ModelFormAddModelForm = self.get_model_form_class()if request.method == "GET":form = AddModelForm()return render(request,'stark/change.html',{'form':form})form = AddModelForm(request.POST) # 接收POST數(shù)據(jù)if form.is_valid(): # 驗(yàn)證數(shù)據(jù)form.save() # 自動(dòng)保存數(shù)據(jù)# 反向生成url,跳轉(zhuǎn)到列表頁面return redirect(self.reverse_list_url())# 渲染頁面,此時(shí)會(huì)保存表單數(shù)據(jù)return render(request, 'stark/change.html', {'form': form})def change_view(self, request, pk):"""所有編輯頁面:param request::param pk::return:"""# 查看單條數(shù)據(jù)obj = self.model_class.objects.filter(pk=pk).first()if not obj:return HttpResponse('數(shù)據(jù)不存在')# 獲取model_form類ModelFormClass = self.get_model_form_class()if request.method == 'GET':# instance表示生成默認(rèn)值form = ModelFormClass(instance=obj)# 渲染頁面,添加和修改可以共用一個(gè)一個(gè)模板文件return render(request, 'stark/change.html', {'form': form})# instance = obj 表示指定給誰做修改form = ModelFormClass(data=request.POST, instance=obj)if form.is_valid():form.save() # 修改數(shù)據(jù)# 跳轉(zhuǎn)到列表頁面return redirect(self.reverse_list_url())return render(request, 'stark/change.html', {'form': form})def delete_view(self, request, pk):"""所有刪除頁面:param request::param pk::return:"""if request.method == "GET":# cancel_url表示用戶點(diǎn)擊取消時(shí),跳轉(zhuǎn)到列表頁面return render(request, 'stark/delete.html', {'cancel_url': self.reverse_list_url()})# 定位單條數(shù)據(jù),并刪除!self.model_class.objects.filter(pk=pk).delete()return redirect(self.reverse_list_url())def wrapper(self, func):@functools.wraps(func)def inner(request, *args, **kwargs):self.request = requestreturn func(request, *args, **kwargs)return innerdef get_urls(self):info = self.model_class._meta.app_label, self.model_class._meta.model_nameurlpatterns = [url(r'^list/$', self.wrapper(self.changelist_view), name='%s_%s_changelist' % info),url(r'^add/$', self.wrapper(self.add_view), name='%s_%s_add' % info),url(r'^(?P<pk>\d+)/change/', self.wrapper(self.change_view), name='%s_%s_change' % info),url(r'^(?P<pk>\d+)/del/', self.wrapper(self.delete_view), name='%s_%s_del' % info),]extra = self.extra_url()if extra: # 判斷變量不為空# 擴(kuò)展路由 urlpatterns.extend(extra)# print(urlpatterns)return urlpatternsdef extra_url(self): # 額外的路由,由調(diào)用者重構(gòu)passdef reverse_list_url(self): # 反向生成訪問列表的urlapp_label = self.model_class._meta.app_labelmodel_name = self.model_class._meta.model_namenamespace = self.site.namespacename = '%s:%s_%s_changelist' % (namespace, app_label, model_name)list_url = reverse(name)# 獲取當(dāng)前請求的_filter參數(shù),也就是跳轉(zhuǎn)之前的搜索條件origin_condition = self.request.GET.get(self.back_condition_key)if not origin_condition: # 如果沒有獲取到return list_url # 返回列表頁面# 列表地址和搜索條件拼接list_url = "%s?%s" % (list_url, origin_condition,)return list_urldef reverse_add_url(self): # 反向生成添加urlapp_label = self.model_class._meta.app_labelmodel_name = self.model_class._meta.model_namenamespace = self.site.namespacename = '%s:%s_%s_add' % (namespace, app_label, model_name)add_url = reverse(name)if not self.request.GET: # 判斷get參數(shù)為空return add_url # 返回原url# request.GET的數(shù)據(jù)類型為QueryDict# 對QueryDict做urlencode編碼param_str = self.request.GET.urlencode() # 比如q=xiao&age=20# 允許對QueryDict做修改new_query_dict = QueryDict(mutable=True)# 添加鍵值對. _filter = param_strnew_query_dict[self.back_condition_key] = param_str# 添加url和搜索條件做拼接add_url = "%s?%s" % (add_url, new_query_dict.urlencode(),)# 返回最終urlreturn add_urldef reverse_edit_url(self, row): # 反向生成編輯行內(nèi)容的urlapp_label = self.model_class._meta.app_label # app名model_name = self.model_class._meta.model_name # 表名namespace = self.site.namespace # 命名空間# 拼接字符串,這里為changename = '%s:%s_%s_change' % (namespace, app_label, model_name)# 反向生成url,傳入?yún)?shù)pk=row.pkedit_url = reverse(name, kwargs={'pk': row.pk})if not self.request.GET:return edit_urlparam_str = self.request.GET.urlencode()new_query_dict = QueryDict(mutable=True)new_query_dict[self.back_condition_key] = param_stredit_url = "%s?%s" % (edit_url, new_query_dict.urlencode(),)return edit_urldef reverse_del_url(self, row): # 反向生成刪除行內(nèi)容的urlapp_label = self.model_class._meta.app_labelmodel_name = self.model_class._meta.model_namenamespace = self.site.namespace# 注意:這里為delname = '%s:%s_%s_del' % (namespace, app_label, model_name)del_url = reverse(name, kwargs={'pk': row.pk})if not self.request.GET:return del_urlparam_str = self.request.GET.urlencode()new_query_dict = QueryDict(mutable=True)new_query_dict[self.back_condition_key] = param_strdel_url = "%s?%s" % (del_url, new_query_dict.urlencode(),)return del_url@propertydef urls(self):return self.get_urls()class AdminSite(object):def __init__(self):self._registry = {}self.app_name = 'stark'self.namespace = 'stark'def register(self,model_class,stark_config=None):# not None的結(jié)果為Tureif not stark_config:# 也就是說,當(dāng)其他應(yīng)用調(diào)用register時(shí),如果不指定stark_config參數(shù)# 那么必然執(zhí)行下面這段代碼!# stark_config和StarkConfig是等值的!都能實(shí)例化stark_config = StarkConfig# 添加鍵值對,實(shí)例化類StarkConfig,傳入?yún)?shù)model_class# self指的是AdminSite類self._registry[model_class] = stark_config(model_class,self)# print(self._registry) # 打印字典"""{app01.models.UserInfo:StarkConfig(app01.models.UserInfo)app02.models.Role:RoleConfig(app02.models.Role)}"""# for k, v in self._registry.items():# print(k,v)def get_urls(self):urlpatterns = []for k, v in self._registry.items():# k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象# k=modes.Role,v=RoleConfig(models.Role) # 封裝:model_class=Role,site=site對象app_label = k._meta.app_labelmodel_name = k._meta.model_nameurlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))return urlpatterns@propertydef urls(self):# 調(diào)用get_urls方法# self.app_name和self.namespace值是一樣的,都是starkreturn self.get_urls(), self.app_name, self.namespacesite = AdminSite() # 實(shí)例化類 View Code?
修改 app01-->stark.py,增加list_filter屬性
from stark.server.stark import site, StarkConfig from app01 import models from django import forms from django.shortcuts import render from django.conf.urls import urlclass UserInfoConfig(StarkConfig):list_display = ['id', 'username']class DepartModelForm(forms.ModelForm):class Meta:model = models.Departfields = "__all__"def clean_name(self): # 定義鉤子# print(self.cleaned_data['name'])return self.cleaned_data['name']class DepartConfig(StarkConfig):list_display = [StarkConfig.display_checkbox,'id','name', 'tel', 'user',StarkConfig.display_edit_del]# model_form_class = DepartModelForm# 批量操作action_list = [StarkConfig.multi_delete,StarkConfig.multi_init]# 搜索字段,如果是跨表字段,要按照ORM語法來search_list = ['name', 'tel', 'user__username']list_filter = ["name","user"] # 組合搜索# def get_add_btn(self): # 返回None,表示不顯示添加按鈕# pass# def changelist_view(self, request): # 重寫changelist_view方法# # 渲染自定義的列表頁面# return render(request,'stark/custom_list.html')# def get_urls(self): # 自定義路由# info = self.model_class._meta.app_label, self.model_class._meta.model_name# # urlpatterns = [# url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),# ]# return urlpatterns site.register(models.UserInfo, UserInfoConfig) site.register(models.Depart, DepartConfig) View Code刷新頁面,查看Pycharm控制臺(tái)輸出:
app01.Depart.name <class 'django.db.models.fields.CharField'> app01.Depart.user <class 'django.db.models.fields.related.ForeignKey'>ForeignKey表示一對多
?
修改?stark-->server-->stark.py,導(dǎo)入模塊ForeignKey,判斷類型。如果是FK,就跨表查詢。
添加list_filter_rows列表,并傳給模板
import functools from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect from types import FunctionType from django.utils.safestring import mark_safe from django.urls import reverse from django import forms from django.db.models import Q from django.http import QueryDict from django.db.models.fields.related import ForeignKeyclass ChangeList(object):"""封裝列表頁面需要的所有功能"""def __init__(self,config,queryset,q,search_list,page):### 處理搜索 ###self.q = q # 搜索條件self.search_list = search_list # 搜索字段self.page = page # 分頁# 配置參數(shù)self.config = config# 批量操作self.action_list = [{'name': func.__name__, 'text': func.text} for func in config.get_action_list()]# 添加按鈕self.add_btn = config.get_add_btn()# ORM執(zhí)行結(jié)果self.queryset = queryset# 顯示的列self.list_display = config.get_list_display()class StarkConfig(object):def __init__(self,model_class,site):self.model_class = model_classself.site = site# 定義request變量,用于非視圖函數(shù)使用。# 在wrapper裝飾器中,對這個(gè)值重新賦值!self.request = None# url中的搜索條件,存在字典中。key為_filterself.back_condition_key = "_filter"def display_checkbox(self,row=None,header=False): # 顯示復(fù)選框if header:# 輸出中文return "選擇"# 注意:這里要寫row.pk,不能寫row.id。你不能保證每一個(gè)表的主鍵都是idreturn mark_safe("<input type='checkbox' name='pk' value='%s' />" % row.pk)def display_edit(self, row=None, header=False):if header:return "編輯"return mark_safe('<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))def display_del(self, row=None, header=False):if header:return "刪除"return mark_safe('<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))def display_edit_del(self, row=None, header=False):if header:return "操作"tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>""" % (self.reverse_edit_url(row), self.reverse_del_url(row),)return mark_safe(tpl)def multi_delete(self, request): # 批量刪除"""批量刪除的action:param request::return:"""pk_list = request.POST.getlist('pk')self.model_class.objects.filter(pk__in=pk_list).delete()# return HttpResponse('刪除成功') multi_delete.text = "批量刪除" # 添加自定義屬性textdef multi_init(self,request): # 批量初始化print('批量初始化')multi_init.text = "批量初始化" # 添加自定義屬性text order_by = [] # 需要排序的字段,由用戶自定義list_display = [] # 定義顯示的列,由用戶自定義model_form_class = None # form組件需要的model_classaction_list = [] # 批量操作方法# 搜索字段,如果是跨表字段,要按照ORM語法來search_list = []list_filter = [] # 組合搜索def get_order_by(self): # 獲取排序列表return self.order_bydef get_list_display(self): # 獲取顯示的列return self.list_displaydef get_add_btn(self): # 顯示添加按鈕return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())def get_model_form_class(self):"""獲取ModelForm類:return:"""if self.model_form_class:return self.model_form_classclass AddModelForm(forms.ModelForm):class Meta:model = self.model_classfields = "__all__"return AddModelFormdef get_action_list(self): # 獲取批量操作方法val = [] # 空列表# 擴(kuò)展列表的元素 val.extend(self.action_list)return valdef get_action_dict(self): # 獲取匹配操作字典val = {}for item in self.action_list:# 以方法名為keyval[item.__name__] = itemreturn valdef get_search_list(self): # 獲取搜索字段val = []val.extend(self.search_list)return valdef get_search_condition(self, request): # 根據(jù)關(guān)鍵字,組合ORM查詢語句search_list = self.get_search_list() # ['name','tel']q = request.GET.get('q', "") # 搜索條件con = Q()con.connector = "OR" # 以O(shè)R作為連接符if q: # 判斷條件不為空for field in search_list:# 合并條件進(jìn)行查詢, __contains表示使用like查詢con.children.append(('%s__contains' % field, q))return search_list, q, condef get_list_filter(self): # 獲取組合搜索條件val = []val.extend(self.list_filter)return valdef changelist_view(self, request):"""所有URL查看列表頁面:param request::return:"""if request.method == 'POST':action_name = request.POST.get('action')action_dict = self.get_action_dict()if action_name not in action_dict:return HttpResponse('非法請求')response = getattr(self, action_name)(request)if response:return response### 處理搜索 ###search_list, q, con = self.get_search_condition(request)# ##### 處理分頁 #####from stark.utils.pagination import Pagination# 總條數(shù)total_count = self.model_class.objects.filter(con).count()# 復(fù)制GET參數(shù)query_params = request.GET.copy()# 允許編輯query_params._mutable = True# 使用分頁類Pagination,傳入?yún)?shù)。每頁顯示3條page = Pagination(request.GET.get('page'), total_count, request.path_info, query_params, per_page=3)# 根據(jù)排序列表進(jìn)行排序,以及分頁功能queryset = self.model_class.objects.filter(con).order_by(*self.get_order_by())[page.start:page.end]cl = ChangeList(self, queryset, q, search_list, page)# ######## 組合搜索 ########## list_filter = ['name','user']list_filter = self.get_list_filter()list_filter_rows = []for field in list_filter:# 如果field = "name" --> 查Depart所有數(shù)據(jù)# 如果field = "user" --> 查UserInfo所有數(shù)據(jù)_field = self.model_class._meta.get_field(field)# print(_field,type(_field)) # 打印字段類型if isinstance(_field,ForeignKey):row = _field.rel.model.objects.all()else:row = self.model_class.objects.all()list_filter_rows.append(row)context = {'cl': cl,'list_filter_rows':list_filter_rows}# 注意:要傳入?yún)?shù)return render(request,'stark/changelist.html',context)def add_view(self, request):"""所有的添加頁面,都在此方法處理使用ModelForm實(shí)現(xiàn):param request::return:"""# 添加數(shù)據(jù),使用ModelFormAddModelForm = self.get_model_form_class()if request.method == "GET":form = AddModelForm()return render(request,'stark/change.html',{'form':form})form = AddModelForm(request.POST) # 接收POST數(shù)據(jù)if form.is_valid(): # 驗(yàn)證數(shù)據(jù)form.save() # 自動(dòng)保存數(shù)據(jù)# 反向生成url,跳轉(zhuǎn)到列表頁面return redirect(self.reverse_list_url())# 渲染頁面,此時(shí)會(huì)保存表單數(shù)據(jù)return render(request, 'stark/change.html', {'form': form})def change_view(self, request, pk):"""所有編輯頁面:param request::param pk::return:"""# 查看單條數(shù)據(jù)obj = self.model_class.objects.filter(pk=pk).first()if not obj:return HttpResponse('數(shù)據(jù)不存在')# 獲取model_form類ModelFormClass = self.get_model_form_class()if request.method == 'GET':# instance表示生成默認(rèn)值form = ModelFormClass(instance=obj)# 渲染頁面,添加和修改可以共用一個(gè)一個(gè)模板文件return render(request, 'stark/change.html', {'form': form})# instance = obj 表示指定給誰做修改form = ModelFormClass(data=request.POST, instance=obj)if form.is_valid():form.save() # 修改數(shù)據(jù)# 跳轉(zhuǎn)到列表頁面return redirect(self.reverse_list_url())return render(request, 'stark/change.html', {'form': form})def delete_view(self, request, pk):"""所有刪除頁面:param request::param pk::return:"""if request.method == "GET":# cancel_url表示用戶點(diǎn)擊取消時(shí),跳轉(zhuǎn)到列表頁面return render(request, 'stark/delete.html', {'cancel_url': self.reverse_list_url()})# 定位單條數(shù)據(jù),并刪除!self.model_class.objects.filter(pk=pk).delete()return redirect(self.reverse_list_url())def wrapper(self, func):@functools.wraps(func)def inner(request, *args, **kwargs):self.request = requestreturn func(request, *args, **kwargs)return innerdef get_urls(self):info = self.model_class._meta.app_label, self.model_class._meta.model_nameurlpatterns = [url(r'^list/$', self.wrapper(self.changelist_view), name='%s_%s_changelist' % info),url(r'^add/$', self.wrapper(self.add_view), name='%s_%s_add' % info),url(r'^(?P<pk>\d+)/change/', self.wrapper(self.change_view), name='%s_%s_change' % info),url(r'^(?P<pk>\d+)/del/', self.wrapper(self.delete_view), name='%s_%s_del' % info),]extra = self.extra_url()if extra: # 判斷變量不為空# 擴(kuò)展路由 urlpatterns.extend(extra)# print(urlpatterns)return urlpatternsdef extra_url(self): # 額外的路由,由調(diào)用者重構(gòu)passdef reverse_list_url(self): # 反向生成訪問列表的urlapp_label = self.model_class._meta.app_labelmodel_name = self.model_class._meta.model_namenamespace = self.site.namespacename = '%s:%s_%s_changelist' % (namespace, app_label, model_name)list_url = reverse(name)# 獲取當(dāng)前請求的_filter參數(shù),也就是跳轉(zhuǎn)之前的搜索條件origin_condition = self.request.GET.get(self.back_condition_key)if not origin_condition: # 如果沒有獲取到return list_url # 返回列表頁面# 列表地址和搜索條件拼接list_url = "%s?%s" % (list_url, origin_condition,)return list_urldef reverse_add_url(self): # 反向生成添加urlapp_label = self.model_class._meta.app_labelmodel_name = self.model_class._meta.model_namenamespace = self.site.namespacename = '%s:%s_%s_add' % (namespace, app_label, model_name)add_url = reverse(name)if not self.request.GET: # 判斷get參數(shù)為空return add_url # 返回原url# request.GET的數(shù)據(jù)類型為QueryDict# 對QueryDict做urlencode編碼param_str = self.request.GET.urlencode() # 比如q=xiao&age=20# 允許對QueryDict做修改new_query_dict = QueryDict(mutable=True)# 添加鍵值對. _filter = param_strnew_query_dict[self.back_condition_key] = param_str# 添加url和搜索條件做拼接add_url = "%s?%s" % (add_url, new_query_dict.urlencode(),)# 返回最終urlreturn add_urldef reverse_edit_url(self, row): # 反向生成編輯行內(nèi)容的urlapp_label = self.model_class._meta.app_label # app名model_name = self.model_class._meta.model_name # 表名namespace = self.site.namespace # 命名空間# 拼接字符串,這里為changename = '%s:%s_%s_change' % (namespace, app_label, model_name)# 反向生成url,傳入?yún)?shù)pk=row.pkedit_url = reverse(name, kwargs={'pk': row.pk})if not self.request.GET:return edit_urlparam_str = self.request.GET.urlencode()new_query_dict = QueryDict(mutable=True)new_query_dict[self.back_condition_key] = param_stredit_url = "%s?%s" % (edit_url, new_query_dict.urlencode(),)return edit_urldef reverse_del_url(self, row): # 反向生成刪除行內(nèi)容的urlapp_label = self.model_class._meta.app_labelmodel_name = self.model_class._meta.model_namenamespace = self.site.namespace# 注意:這里為delname = '%s:%s_%s_del' % (namespace, app_label, model_name)del_url = reverse(name, kwargs={'pk': row.pk})if not self.request.GET:return del_urlparam_str = self.request.GET.urlencode()new_query_dict = QueryDict(mutable=True)new_query_dict[self.back_condition_key] = param_strdel_url = "%s?%s" % (del_url, new_query_dict.urlencode(),)return del_url@propertydef urls(self):return self.get_urls()class AdminSite(object):def __init__(self):self._registry = {}self.app_name = 'stark'self.namespace = 'stark'def register(self,model_class,stark_config=None):# not None的結(jié)果為Tureif not stark_config:# 也就是說,當(dāng)其他應(yīng)用調(diào)用register時(shí),如果不指定stark_config參數(shù)# 那么必然執(zhí)行下面這段代碼!# stark_config和StarkConfig是等值的!都能實(shí)例化stark_config = StarkConfig# 添加鍵值對,實(shí)例化類StarkConfig,傳入?yún)?shù)model_class# self指的是AdminSite類self._registry[model_class] = stark_config(model_class,self)# print(self._registry) # 打印字典"""{app01.models.UserInfo:StarkConfig(app01.models.UserInfo)app02.models.Role:RoleConfig(app02.models.Role)}"""# for k, v in self._registry.items():# print(k,v)def get_urls(self):urlpatterns = []for k, v in self._registry.items():# k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象# k=modes.Role,v=RoleConfig(models.Role) # 封裝:model_class=Role,site=site對象app_label = k._meta.app_labelmodel_name = k._meta.model_nameurlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))return urlpatterns@propertydef urls(self):# 調(diào)用get_urls方法# self.app_name和self.namespace值是一樣的,都是starkreturn self.get_urls(), self.app_name, self.namespacesite = AdminSite() # 實(shí)例化類 View Code修改?stark-->templates-->stark-->changelist.html,for循環(huán)list_filter_rows列表
{% extends 'stark/layout.html' %} {% load stark %}{% block css %}<style>.comb-search {padding: 5px 20px;}.comb-search .row .whole {width: 60px;float: left;}.comb-search .row .others {padding-left: 60px;}.comb-search .row a {display: inline-block;padding: 5px 8px;margin: 3px;border: 1px solid #d4d4d4; }.comb-search .row a {display: inline-block;padding: 5px 8px;margin: 3px;border: 1px solid #d4d4d4; }.comb-search a.active {color: #fff;background-color: #337ab7;border-color: #2e6da4; }</style> {% endblock %} {% block content %}<div>{#組合搜索#}<div class="comb-search">{% for row in list_filter_rows %}<div class="row"><div class="whole"><a href="#">全部</a></div><div class="others">{% for obj in row %}<a href="#">{{ obj }}</a>{% endfor %}</div></div>{% endfor %}</div>{#添加按鈕#}{% if cl.add_btn %}<div style="margin: 5px 0;">{{ cl.add_btn }}</div>{% endif %}{#搜索框#}{% if cl.search_list %}<div style="float: right;"><form method="GET" class="form-inline"><div class="form-group"><input class="form-control" type="text" name="q" value="{{ cl.q }}" placeholder="關(guān)鍵字搜索"><button class="btn btn-primary" type="submit"><i class="fa fa-search" aria-hidden="true"></i></button></div></form></div>{% endif %}<form class="form-inline" method="post">{% csrf_token %}{#批量操作#}{% if cl.action_list %}<div class="form-group"><select name="action" class="form-control" style="min-width: 200px;"><option>請選擇功能</option>{% for item in cl.action_list %}<option value="{{ item.name }}">{{ item.text }}</option>{% endfor %}</select><input class="btn btn-primary" type="submit" value="執(zhí)行"></div>{% endif %}{#使用table展示數(shù)據(jù)#}{% table cl %}{#分頁展示#}<nav aria-label="Page navigation"><ul class="pagination">{{ cl.page.page_html|safe }}</ul></nav></form></div>{% endblock %} View Code刷新頁面,效果如下:
?
?
?
?
?
?
后臺(tái)搜索
?
關(guān)于后面的詳細(xì)步驟,沒有時(shí)間寫了。附上完整代碼:
鏈接:https://pan.baidu.com/s/1fLOGH_3G7hPTvCYKX84UdQ 密碼:m8rh
?
七、領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)
什么是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)
2004年著名建模專家Eric Evans發(fā)表了他最具影響力的書籍:《Domain-Driven Design –Tackling Complexity in the Heart of Software》(中文譯名:領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)—軟件核心復(fù)雜性應(yīng)對之道),書中提出了“領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(簡稱 DDD)”的概念。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)事實(shí)上是針對OOAD的一個(gè)擴(kuò)展和延伸,DDD基于面向?qū)ο蠓治雠c設(shè)計(jì)技術(shù),對技術(shù)架構(gòu)進(jìn)行了分層規(guī)劃,同時(shí)對每個(gè)類進(jìn)行了策略和類型的劃分。
領(lǐng)域模型是領(lǐng)域驅(qū)動(dòng)的核心。采用DDD的設(shè)計(jì)思想,業(yè)務(wù)邏輯不再集中在幾個(gè)大型的類上,而是由大量相對小的領(lǐng)域?qū)ο?類)組成,這些類具備自己的狀態(tài)和行為,每個(gè)類是相對完整的獨(dú)立體,并與現(xiàn)實(shí)領(lǐng)域的業(yè)務(wù)對象映射。領(lǐng)域模型就是由這樣許多的細(xì)粒度的類組成。基于領(lǐng)域驅(qū)動(dòng)的設(shè)計(jì),保證了系統(tǒng)的可維護(hù)性、擴(kuò)展性和復(fù)用性,在處理復(fù)雜業(yè)務(wù)邏輯方面有著先天的優(yōu)勢。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的特點(diǎn)
領(lǐng)域驅(qū)動(dòng)的核心應(yīng)用場景就是解決復(fù)雜業(yè)務(wù)的設(shè)計(jì)問題,其特點(diǎn)與這一核心主題息息相關(guān):
?
舉例:商品價(jià)格
一個(gè)商品,有商品名(name),原價(jià)(price),折扣價(jià)(discount)。如何用類來表示呢?
常規(guī)類
class Goods(object):def __init__(self,name,price,discount):self.name = nameself.price = priceself.discount = discount如果要增加優(yōu)惠券(滿減,立減,折扣),怎么辦?
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)
class BaseCoupon(object):"""優(yōu)惠券基礎(chǔ)類"""passclass Coupon1(BaseCoupon):"""滿減"""passclass Coupon2(BaseCoupon):"""立減"""passclass Coupon3(BaseCoupon):"""折扣"""passclass Price(object):"""商品價(jià)格"""def __init__(self,price,discount):self.price = priceself.discount = discountdef pay(self): # 交易價(jià)格passclass Goods(object):def __init__(self,name):self.name = name View Code重點(diǎn)就是建模
一般做3年開發(fā),就可以領(lǐng)悟 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)。具體還得看個(gè)人的領(lǐng)悟能力!
?
其他更多信息,請參考鏈接:
https://www.cnblogs.com/yihaha/p/3977496.html
?
關(guān)于python方面領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的相關(guān)書籍,暫時(shí)還沒有。
主流的是JAVA,C#,PHP
?
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)它是一種編程思想,重點(diǎn)就是建模!對于開發(fā)一個(gè)大型項(xiàng)目,尤為重要!
在python源代碼中,就利用這種思想。類中層層嵌套類!
對于個(gè)人編程能力的提升,可以看一下相關(guān)書籍!
?
未完待續(xù)...
轉(zhuǎn)載于:https://www.cnblogs.com/xiao987334176/p/9575783.html
總結(jié)
以上是生活随笔為你收集整理的python 全栈开发,Day116(可迭代对象,type创建动态类,偏函数,面向对象的封装,获取外键数据,组合搜索,领域驱动设计(DDD))...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 移植madplay到jz2440【学习笔
- 下一篇: JAVA基础知识总结8(设计模式)