关于模拟admin实现stark组件的知识点
一. url知识
还记得include分发么?里面的参数都可以有些什么?
urlconf_module本质是返回的是模块路径对象
def include(arg, namespace=None, app_name=None): ....... return (urlconf_module, app_name, namespace)
1. 字符串格式?
url(r'^joker/', include('app01.urls')),
源码解释。
patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module)
通过反射找到urlconf_moduls模块下的urlpatterns,如果没有urlpatterns会报错
2. 列表格式?
url(r'^joker/', include([ url('login1', login), ])),
源码解释。
if isinstance(arg, tuple): ....... else: # No namespace hint - use manually provided namespace urlconf_module = arg
走else,也就是urlconf_moduls返回的就是这个列表
3 元祖?
url(r'^joker/', ([ url('app01/',([(url('login',login))],None,None)), url('login2',login), ],None,None)),
源码解释。
return (urlconf_module, app_name, namespace)
include分发本质返回的就是,url模块,app名字,命名空间,那我们直接把这个元祖写这里,相当于分发
最后,上面都是前面与后面的拼接成url
2. 装饰器
我们给视图函数(增删改查)加上了装饰器,其目的是让每个url都是个request对象,为了携带当前访问时候的数据
当时的代码如下
self.request = None 类属性当时为None # 携带数据装饰器 def warp(self, view_func): def inner(request, *args, **kwargs): self.request = request ###### 每个增删改查在点击的时候都携带REQUEST这个数据 return view_func(request, *args, **kwargs) return inner # LIST_VIEW = WARP(LIST_VIEW) == INNER (LIST_VIEW) == # URL def get_urls(self): # 默认的增删改查 # 我这里获取的URL是不是应该加入别名?反向解析呢? # url( 正则,视图(元祖,列表),命名空间) app_model_name = (self.model._meta.app_label, self.model._meta.model_name) # 应用名称,表名称 temp = [ url("^$", self.warp(self.list_view), name="%s_%s_list" % app_model_name), url("^add/$", self.warp(self.add_view), name="%s_%s_add" % app_model_name), url("^(\d+)/edit/$", self.warp(self.edit_view), name="%s_%s_edit" % app_model_name), ### 注意小括号 url("^(\d+)/delete/$", self.warp(self.delete_view), name="%s_%s_delete" % app_model_name), ] return temp
装饰器学习
http://www.cnblogs.com/jokerbj/p/7247901.html
3. model取值操作
常规取值操作
http://www.cnblogs.com/jokerbj/p/8145387.html
针对表对象可以取一些特定的值,比如咱们的代码
# 注册,这是在启动的时候就会加载的 joker.site.register(models.Book) # 针对model取值 model_name = model._meta.model_name # 数据库表名 app_label = model._meta.app_label # 应用表名 # 取表字段 verbox_name=self.model._meta.get_field('title').verbose_name # 如果 model里面没有指定verbose_name就是字段名,指定就是verbose_name对应的值
_field.rel.to.objects.all() # _field 是字段,拿到的是该字段的所有值
针对Q查询,看下咱们代码
condition = Q() # 利用Q 查询 condition.connector = 'or' # 指定Q查询之间是什么关系 if key_word and self.show_search_form: # 有默认搜索值,并且前端开启页面 for field_name in search_fields: # 'title__contains','price', condition.children.append((field_name,‘joker’)) # title=joker的值或者price=joker的值 print(condition) 数据查询这块就是 queryset = self.model.objects.filter(self.get_search_condition()) # 过滤条件
4. request.GET.urlencode() 携带数据跳转
我们之前为了保持每次搜索携带数据,引入了request.get.urleode方法,这个方法可以使请求的数据直接变成字符串
# 例如访问的url http://127.0.0.1:8000/?page=1&id=2 # 如果我们用将这次请求利用request.GET.urlencode()打印 得到 page=1&id=2 的字符串 # 我们携带这个数据进入要编辑页面,当我们编辑完我们还会携带这个数据,返回之前我们页面,所以说这个数据就是当前页面的状态
有个问题?
如果请求携带的数据有重复怎么办?
我们引入QueryDict这个字典,因为普通的字典无法被urlencode,打开request.GET修改?
# queryset dict from django.http import QueryDict # 获取当前请求头 query_str = self.request.GET.urlencode() # 请求数据 # QueryDict 字典加入值 parames = QueryDict(mutable=True) # 允许更改request.GET mutable 可变的意思 parames[self._query_param_key] = query_str # 加入当前URL数据 # 好了之后,反问哪个就加入下面经过urlencode处理的数据 return mark_safe("<a href='%s?%s'>edit</a>" % (a,b,parames.urlencode())) # 调用反向解析出来的url,就是这样携带数据访问 # 后端处理数据后,返回的页面就是携带之前的数据 list_query_str = request.GET.get(self._query_param_key) list_url = "%s?%s" % (self.get_list_url(), list_query_str,) return redirect(list_url)
强插一个知识点》》
config.request.GET.get(config.search_key,'')
如果没有获取不到该值,可以给个默认值空。当然也可以为别的,默认是None
强插一个知识点》》
_params.setlist(self.option.field_name,id_list) # 重新设置请求 url = '{0}?{1}'.format(self.request.path_info, _params.urlencode())
可以传入列表,元祖,重新赋值
5. button可以提交数据?
有时html页面button点击会出现自动提交表单的情况。
<form action="" method="post"> {% csrf_token %} <input type="text" placeholder="xxx"> <button></button> </form>
form表单下的按钮在没有指定type类型的时候,button会有一个默认的type=”submit”
给button设置一个类型type="button",这样button的类型就不是默认的submit了,就不会自动提交表单了
<form action="" method="post"> {% csrf_token %} <input type="text" placeholder="xxx"> <button type="button"></button> </form>
6. 模版语言里面不能用_ or __ 去调用
{{ cls._pk }}
{{ cls.__pk }}
7. 判断字段是不是外键,或者多对多关系
from django.db.models import ForeignKey,ManyToManyField if isinstance(_field,ForeignKey): pass
8. 取choices字段中文
device_status_choices = (
(1, '上架'),
(2, '在线'),
(3, '离线'),
(4, '下架'),
)
device_status_id = models.IntegerField(choices=device_status_choices, default=1)
return obj.get_gender_display()
# 这里用法就是 get_fieldname_display() fieldname device_status_di中间加入字段就会自动拿到CHOICE对应的中文拿到前提就是这个对象有这个字段
# 前端 <td>{{ data.asset.get_device_status_id_display }}</td> 这样获取
9 . 单例模式
class Foo(object): _instance = None def __init__(self, name): self.name = name @classmethod def instance(cls, *args, **kwargs): if not Foo._instance: obj = Foo(*args, **kwargs) Foo._instance = obj return Foo._instance obj1 = Foo.instance('alex') obj2 = Foo.instance('alex') print(id(obj1), id(obj2))
10. 反射
### settings
# DB_PATH = "db.mysql.MySQLHelper" DB_PATH = "db.sqlserver.SqlServerHelper"
### db 下的mysql/sqlserverPY文件
class MySQLHelper(object):
def fetchone(self):
"""
链接MySQL,获取一条数据
:return:
"""
print('MySQL.fetchone')
### app.py from settings import DB_PATH # 我导入一段字符串 def func(): # 导入文件 # 反射 # DB_PATH = "db.mysql.MySQLHelper" module_path, cls_name = DB_PATH.rsplit('.', maxsplit=1) # db.mysql / db.sqlserver # 以字符串的形式导入模块 # from db import mysql 类似于 这种 import importlib 导入模块 module_obj = importlib.import_module(module_path) # # 去模块中导入类 cls = getattr(module_obj, cls_name) cls_name 是模块下的类 # 类实例化 obj = cls() obj.fetchone() if __name__ == '__main__': func()
11. 对象封装数据
class Foo(object): def __init__(self, name, data_list): self.name = name self.data_list = data_list def __iter__(self): yield "<div>" yield "全部" for item in self.data_list: yield item yield "</div>" obj_list = [Foo('富贵', ['男', '女']), Foo('强哥', ['已报名', '未报名']), Foo('熊平', ['内部转介绍', '百度推广'])] # 需求:循环对象时,先打印对象name属性,然后再答应123。 for obj in obj_list: for item in obj: print(item)
12. 弹出popup
三种window对象,弹出关闭 window.alert(123); 关闭 window.confirm("123"); 交互 取消 关闭 window.prompt("123"); 输入内容 取消 关闭
############################# url代码 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), url(r'^pop/', views.pop), ] ############################ views代码 def index(request): return render(request, 'index.html') def pop(request): if request.method == "GET": return render(request, 'pop.html') else: user = request.POST.get('user') return render(request, 'pop_response.html', {'user': user}) ############################ index.html代码 <h1 id="i1">我会被更改的</h1> <a href="#" onclick="popUp('http://www.oldboyedu.com')">点我点我</a> <script> function xxxpopupCallback(text) { document.getElementById('i1').innerHTML = text; } function popUp(url) { window.open('/pop/', "n1", "status=1, height:500, width:600, toolbar=0, resizeable=0"); } </script> ########################### pop.html代码 <form method="post"> {% csrf_token %} <input type="text" name="user"> <input type="submit" value="保存"> </form> ########################### pop_response代码 <h1>正在关闭</h1> <script> (function () { // 可以调用popup原页面的一个函数 opener.xxxpopupCallback("{{ user }}"); window.close(); })() </script>
流程解释:
我们访问到index页面,利用事件让浏览器弹出一个我们自定义的窗口(window.open),在这个窗口中我们给予他需要弹出的页面pop.html页面,并设置xxxpopupCallback接收到时候儿html的返回值。提交表单post发回视图,视图转给pop_response页面,匿名函数返回给源html值,opener.xxxpopupCallback("{{ user }}");随后关闭。
13. form表单补充
数据实时更新
方式一 class RegForm(forms.Form): user = forms.CharField(max_length=32) #gender_tuple=(0,'上海'),(1,'北京'),(2,'保定') gender = forms.ChoiceField(choices =City.objects.all().values_list("id","name")) # 第一次启动时候数据拿了一遍,无法实时更新,如果数据更新了,页面显示不出来 def __init__(self,*args,**kwargs): super(RegForm,self).__init__(*args,**kwargs) # 通过构造方法实时更新 #print("Ok") print(self.fields["gender"].choices) self.fields["gender"].choices=City.objects.all().values_list("id","name") 方式二 依赖 MODEL from django.forms import ModelChoiceField,MultipleChoiceField class RegForm(forms): gender = fields.ModelChoiceField(queyset=City.objects.all()) # 字段 页面单选 class RegForm(forms): gender = fidles.MultipleChoiceField(queyset=City.objects.all()) # 字段 页面多选 # 方式三 class RegForm(ModelForm): # 依赖MODEL,同方式二, class Meta: model = UserInfor # 如果UserInfor是F,就生成ModelChoiceField,是M2,就生成MultipleChoiceField fields = "__all__"
modelform转变form
class RegForm(ModelForm): # 依赖MODEL,同方式二, class Meta: model = UserInfor # 如果UserInfor是F,就生成ModelChoiceField,是M2,就生成MultipleChoiceField fields = "__all__"
读取model = userinfo中的字段,转变成form字段
class UserInfor(models.Model): user=models.CharField(max_length=32) gender=models.IntegerField(choices=((1,"男"),(2,"女"))) city=models.ForeignKey("City",default=1) roles=models.ManyToManyField("Roles",default=1) ||||| class UserInfor(forms.Form): user=forms.CharField() gender=forms.TypedChoiceField(choices=((1,"男"),(2,"女"))) city=forms.ModelChoiceField(choices=City.objects.all()) roles=forms.ModelMultipleChoiceField(choices=Roles.objects.all())
循环form
def reg(reqeust): form = RegForm() # form包含了表内的所有字段 for i in form: print(i) <input type="text" name="user" required id="id_user" maxlength="32" /> 因为内部的str方法才显示的标签,不过还是个对象,这个是前端渲染框的
print(i.field) # <django.forms.fields.CharField object at 0x1068d1c88> boundield 里面的field字段打印就是每个字段的类型
print(type(i)) <class 'django.forms.boundfield.BoundField'>,每个字段都是对象,被boundfield封装
前端页面 {{ field.label }},打印的是字段名称,如果有verbose_name打印这个,没有打印字段名字
源form学习
http://www.cnblogs.com/jokerbj/p/8157669.html