关于模拟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
stark用装饰器源码

装饰器学习

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__"
View Code

 

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

 

posted @ 2018-02-02 02:00  liqianlong  阅读(319)  评论(0编辑  收藏  举报