django 复习(杂)

目录

常用命令

get和post请求

自定404和500错误

session 设置过时时间

request的几个方法

引入django的设置中的变量

简单请求与复杂请求

利用dajngo自带的ContentType

感觉没啥鸡儿用的django管理器

添加管理器

自定义管理器

Queryset

Queryset缓存机制

Queryset求值情况(惰性查询)

F和Q

F:

Q : Q函数队关键字进行封装, 从而更好地应用多个查询&, | , ~

三个神奇的内置方法

关于update()

admin 注册

布尔字段

多对多添加删除

静态字段(只有choice)

1)重写__init__

2)自动更新(ModelChoiceField)

mark_safe

ajax

is_ajax

ajax的data只能时字符串或数字, 但有数组时

当有字典时

ajax发post

1)加csrf_token

2) 别人写的setupajax.js

跨域

ajax跨域

一   jsonp

二  cors跨域

form表单字段

下拉框

单选框

复选框

判断forn或modelform渲染的字段是不是一对多或多对多

form组件的limit_chocie_to={}  

model一些属性

model的get_字段_display()

mode的Meta:

getlist(获取多个值)

CBV

csrf_exempt装饰器

csrf_protect装饰器

url分组匹配

1)url

2) 分组命名匹配

url 分流

url的分发匹配

一级分发

二级分发

多条url访问一个函数(xx/app的名字/表的名字)

模仿admin的url, 实现批量生成app的表的增删改查url

url 反向解析

1) url

2) 模板

3)后台

当url有参数时

url反向解析的命名空间

在python脚本中加载dango项目

Django的一些常用方法

1)get() 和 filter()

2) exclude()  排除

3) values()

4)values_list()

5)order_by()

6)reverse()      只能将排过序的的逆序

7) distinct()    

8)first(),last()  

9) exists()     Queryset有数据返回True, 没数据返回False

10) count()  计数

11)双下划线

12)only和defer

13) bulk_create()  批量插入数据

14)extra()     执行额外的数据库查询

15) select_related()

16) prefetch_related()

17)   总结

返回Queryset的

返回集体对象的

返回布尔值

返回具体数字

外键查找

正向(从有外键的一方)

反向

手动创建第三张表

 

分组和聚合 外加 extra() 额外执行查询

聚合

分组

分组的跨表:(在我看来就是玄学)

coikie

session

一个js小demo(通过iput失去焦点向后端发送ajax请求, 可以实时看看有没有重名之类的)

中间件

上传文件到服务器指定位置

Django的密码(把明文密码换成密文)


常用命令

python manage.py startapp app_name

python manage.py runserver

python manage.py makemigrations

python manage.py migrate

python manage.py createsuperuser 

python manage.py flush           清空数据库

python manage.py changepassword username                             修改用户名的密码

python manage.py dumpdata appname > appname.json  导出数据

python manage.py loaddata appname.json          导入数据

python manage.py shell                                                                  进入终端

python manage.py dbshell                        进入数据库,然后就可以输入sql

 

get和post请求

get请求类似于 “GET url ?a=1&b=2  http/1.1\r\user_agent:Google\r\ncontentType:urlencode\r\n\r\n'”

post请求类似于 "POST url http/1.1\r\user_agent:Google\r\nconteneType:urlencode\r\n\r\na=1&b=2"

request.body   a=1&b=2   (如果是get请求, body没数据)

request.POST  是contentType=urlencode   才有返回值 返回 {’a‘:1, 'b'"2}

 

 

自定404和500错误

1. 首先在settings中设置

DEBUG = False

ALLOWED_HOSTS = ["*"]

2. 在url中

handler500 = views.page_not_found
handler404 = views.page_not_found

网上很多教程说要引入下面的,但实际操作引入pycahrm警告, 不引入正常, 上面404和500 都设置成了一个函数

from django.conf.urls import handler404, handler500

3. views中

from django.shortcuts import render_to_response

def page_not_found(request):
    return render_to_response('404.html')

session 设置过时时间

1 .request.session.set_expiry(value)

  • 如果value是个整数,session会在些秒数后失效(适用于整个Django框架,即这个数值时效时整个页面都会session失效)。
  • 如果value是个datatime或timedelta,session就会在这个时间后失效。
  • 如果value是0,用户关闭浏览器session就会失效。
  • 如果value是None,session会依赖全局session失效策略。

2. settings中

  • SESSION_COOKIE_AGE=60*30 30分钟。
  • SESSION_EXPIRE_AT_BROWSER_CLOSE False:会话cookie可以在用户浏览器中保持有效期。True:关闭浏览器,则Cookie失效。
  • SESSION_COOKIE_DOMAIN 生效站点
  • SESSION_COOKIE_NAME cookie中保存session的名称
  • SESSION_SAVE_EVERY_REQUEST为True

 

request的几个方法

url = 127.0.0.1:8000/index.html/?p=11&c=6

print(request.GET)                                 < Queryset:{'p':['11'], 'c':['6']} >

print(request.path_info)                         /index.html/

print(request.path)                                 /index.html/

print(request.get_full_path())                /index.html?p=11&c=6/

a = requet.GET

print(a.urlencode)                                p=1&c=6

print(request.get_host)                      127.0.0.1:8000

 

引入django的设置中的变量

from django.conf import settings


if limit != settings.INVITATION_CODE:
     raise ValidationError("邀请码不对,请找管理员核对")

 

简单请求与复杂请求

概述简单请求发啥请求方式就是啥请求,复杂请求发之前会先发options请求,进行预检,预检不通过,则发的复杂请求也不会通过

简单请求:

1)请求方式为HEAD, GET, POST

2) 请求头信息为:

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

同时满足两个条件时, 是简单请求, 否则为复杂请求。

复杂请求:

先发options进行预检, 预检不通过,本身想发的请求也不通过。

 

对于复杂的请求:

可以写个中间件把复杂请求变成简单请求

from django.utils.deprecation import MiddlewareMixin


class CORSMiddleware(MiddlewareMixin):

    def process_response(self, request, response):
        # response['Access-Control-Allow-Orign'] = "*"
        # 允许全部域名获取数据
        # response["Access-control-Allow-Headers"] = "Content-Type"
        # 允许携带的xx请求头
        # response["Access-Control-Allow-Methods"] = "xx"
        # 允许的请求方式, 如写 PUT
        response['Access-Control-Allow-Orign'] = "*"
        if request.method == 'OPTIONS':
            response["Access-control-Allow-Headers"] = "Content-Type"
        return response

 

利用dajngo自带的ContentType

引自https://www.jianshu.com/p/f2285d77cddd

实现多表关联

  • 在model中定义ForeignKey字段,并关联到ContentType表,通常这个字段命名为content-type
  • 在model中定义PositiveIntergerField字段, 用来存储关联表中的主键,通常我们用object_id
  • 在model中定义GenericForeignKey字段,传入上面两个字段的名字
  • 方便反向查询可以定义GenericRelation字段

models.py

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation

class Appliance(models.Model):
    """
    家用电器表
    id name
    1   冰箱
    2   电视
    3   洗衣机
    """
    name = models.CharField(max_length=64)
    coupons = GenericRelation(to="Coupon")  
    # 反向查找


    def __str__(self):
        return self.name

class Food(models.Model):
    """
    食物表
    id name
    1  面包
    2  牛奶
    """
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

class Fruit(models.Model):
    """
    水果表
    id  name
    1   苹果
    2   香蕉
    """
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

class Coupon(models.Model):
    """
    优惠券表
    id  name    appliance_id    food_id     fruit_id
    1   通用优惠券   null            null        null
    2   冰箱折扣券   1               null        null
    3   电视折扣券   2               null        null
    4   苹果满减卷   null            null        1
    我每增加一张表就要多增加一个字段
    """
    name = models.CharField(max_length=32)
    # 第一步
    content_type = models.ForeignKey(to=ContentType)
    # 第二步
    object_id = models.PositiveIntegerField()
    # 第三步
    content_object = GenericForeignKey('content_type', 'object_id')

    def __str__(self):
        return self.name

view.py

from django.shortcuts import render, HttpResponse
from django import views
from app01 import models

class Text(views.View):

    def get(self, request):
        # 通过ContentType获得表名
        content = models.ContentType.objects.filter(app_label="app01", model="appliance").first()
        # 获得表model对象 相当于models.Applicance
        model_class = content.model_class()
        obj_list = model_class.objects.all()

        # 创建:给电器的冰箱添加优惠券
        # 第一步,将想要添加优惠券的对象取出
        obj = models.Appliance.objects.filter(pk=2).first()
        # 第二步,创建优惠券,传入两个参数name="冰箱优惠券", content_object=obj
        models.Coupon.objects.create(name="冰箱优惠券", content_object=obj)

        # 正向查询:查询优惠券id=1绑定了哪个商品
        Coupon_obj = models.Coupon.objects.filter(pk=1).first()
        goods_obj = Coupon_obj.content_object
        print(goods_obj)

        # 反向查询之定义了coupons = GenericRelation(to="Coupon")
        appliance_obj = models.Appliance.objects.filter(pk=2).first()
        results = appliance_obj.coupons.all()
        print(results)

        # 反向查询之没有定义coupons = GenericRelation(to="Coupon")
        result = models.Coupon.objects.filter(content_type=content, object_id=2)
        print(result)

        return HttpResponse("ok")

 

感觉没啥鸡儿用的django管理器

添加管理器

from django.db import  models
class BookManger(model.Manger):
    def title_count(self, keyword):
        return self.filter(title__contains=keyword).count()
    
class Book(modles.Model):
    ...
    object = BookManger()  # 加一个管理器, 可能覆盖原来的管理器

使用时
Book.objects.title_count('django')

自定义管理器

class MaleMager(models.Mager):
    def get_queryset(self):
        return super(MaleManger, self).get_queryset().filter(sex='M')

class FamaleMager(models.Manger):
    def get_queryset(self):
        return super().get_queryset().filter(sex='F')

class Person(models.Model):
     people = models.Manger()    # 默认的管理器
     men = MaleManager()
     women = FamaleMager()

使用时
xx.people.all()
xx.men.count()

 

Queryset

  1. 可切片(没有负数)
  2. 可迭代
  3. 惰性查询
  4. 缓存机制

iterator: 迭代数据

当queryset非常大时, 它一次获取一部分数据, 然后删除

objs = Book.objects.all().iterator()
for obj in objs:
    print(obj.title)

for obj in objs:
    print(obj.title)

# 第一正常有数据, 第二次没有结果, 因为第一次, 边遍历边删除, 第二次就没有结果了

 

Queryset缓存机制

就是说,查询数据库并不是实时的,如果查询过程中,数据库有增减,结果不会变,有缓存

print([a.create_time for a in model.Art.objects.all()])

如上, 数据库有变化时, 结果却相同, 因为有缓存

解决办法: 定义变量

queryset = models.Art.objects.all()

print([a.title for a in query])

 

Queryset求值情况(惰性查询)

  1. 第一次迭代Queryset(遍历时。
  2. 执行切片操作时    Post.objects.all()[:3]。
  3. pickled 或缓存Queryset时。(pickled 是它的序列化, 很不常用)
  4. 调用repr()和 len() 时  (repr相当于__str__不常用)
  5. 调用list()
  6. 逻辑判断时, bool(), or  and if 

 

 

F和Q

F:

from django.db.models import Q, F

Book.objects.all().update(price=F("price") + 10)

Q : Q函数队关键字进行封装, 从而更好地应用多个查询&, | , ~

1)

ret = Book.objects.filter(Q(price=xx) | Q(name='xx'))

2)

from django.filter.models import Q

q = Q()
q.connection = "or"       # 默认是and
q.children.append(("title", "XX"))     # 可以传字符串形式的键
q.children.append(("price", "123"))
models.Tb1.objects.filter(q)
con = Q()

q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 2))
q1.children.append(('id', 3))

q2 = Q()
q2.connector = 'OR'
q2.children.append(('status', '在线'))

con.add(q1, 'AND')
con.add(q2, 'AND')

models.Tb1.objects.filter(con)

 

个人瞎鸡总结:

F能进行数学运算, Q对数据进行筛选

注意:

Book.objects.filter(Q(name='xx'), price=xx)

Q必须放在前面

 

 

三个神奇的内置方法

Order._meta.app_label                  # ’app01‘,    能找到order表属于的app, 是一个字符串

Order._meta.model_name                 # 'order', 找到Order表的名字, 是一个字符串

field_obj = Order._meta.fields         #  拿到所有字段

for i in field_obj:

    print(i.verbose_name)               # 要是字段没有这个属性返回字段名,多对多不打印

title = Order._meta.get_field('title')  # 拿到Order表的title字段, 结果为app01.Order.title,

print(title.max_length)                 # 返回 32 返回的是title属性的值

 

 

关于update()

Pulisher.objects.filter(id=2).update()

不能用get代替filter

 

 

admin 注册

from app001 import models

admin.site.register(models.Auth)

 

 

布尔字段

sex = models.BooleanField(max_length=1, choices=((0, '女'), (1, '男')), null=False)

 

 

多对多添加删除

m = models.ManyToManyField('Teacher', on_delete=models.CASCADE)
obj = class.objects.filter(id=1).first()
obj.m.add(2)
obj.madd(3)
obj.m.add([2, 3])
obj.m.remove([2, 3])     # 删除指定
obj.m.clear()            # 清空全部
obj.m.set(2, 3, 4)       # 全部重置

 

 

静态字段(只有choice)

实时刷新, 不用重启django

1)重写__init__

from django import forms
from django.forms import widgets, fields


class A(forms.Form):
    price = fields.IntegerField()
    user_id = fields.IntegerField(
        widget=widgets.Select()
        # widget=widgets.Select(choices=models.Userinfo.objects.valuse_list('id', 'username'))
        # 实际要查上面的, 但是每次最先加载__init__, 加载init时就已经查找完了, 在这里如果再查找就重复了
    )

    def __init__(self, *args, **kwargs):
        super(A, self).__init__(*args, **kwargs)
        self.fields['user_id'].widget.choices = models.Userinfo.objects.valuse_list('id', 'username')

2)自动更新(ModelChoiceField)

在views.py中的form写法

class UserForm(forms.Form):
    username = ModelChoiceField(queryset=models.UserInfo.objects.all(), to_field_name='指定在数据库的叫什么')

但是也带来了前端显示不正常的问题

所以要在models中加

from django.db import models


class UserInfo(models.Model):
    username = models.CharField(max_length=33)
    
    def __str__(self):
        return self.username

 

 

mark_safe

后端传html, 也可以用模板的{{ | safe }}

from django.utils.safestring import mark_safe


def text(quest):
    txt = "<input type='test >"
    text = mark_safe(txt)
    return ......   

 

 

ajax

is_ajax

def xx():
   if request.is_ajax():
       ....
   else:
   # get请求 
$.ajax({
    url: '',
    type: 'POST',
    data: {'k1': 'v1'},
    dataType: 'JSON',
    {#能将arg反序列化, 转化为js对象#}
    success: function (arg) {
        
    }
})

ajax的data只能时字符串或数字, 但有数组时

$.ajax({
    url: '',
    type: 'POST',
    data: {'k1': [1, 2, 3]},
    dataType: 'JSON',
    {#能将arg反序列化, 转化为js对象#}
    traditional: true,
    success: function (arg) {

    }
})

当有字典时

$.ajax({
    url: '',
    type: 'POST',
    data: {'k1': JSON.stringify({'a': 1})},
    dataType: 'JSON',
    {#能将arg反序列化, 转化为js对象#}
    traditional: true,
    success: function (arg) {
    }
})

 

ajax发post

ajax 发送post请求默认会禁止

下面说几种跨域方法

1)加csrf_token

{% csrf_token %}
<input ... >

就是input发送的ajax请求, 加个csrf_token

然后ajax把它发送过去

var il = $('#i2').val();
var csrfToken = $("[name='csrfmiddlewarewoken']").val();
$.ajax({
    url: "",
    type: "POST",
    data: {'i1': i1, 'csrfmiddlewaretoken':csrfToken},
    success: function (arf) {
    }
})

2) 别人写的setupajax.js

直接在前端引入它 <script src="/static/setupajax.js"></script>

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});

 

跨域

ajax跨域

一   jsonp

原理:通过<script>发get请求

jsonp只能发get请求

可以不写jsonpCallback参数

不写jsonpCallback参数时, 相当于向http://127.0.0.1:8008/service/callback=随机字符串  发get请求

有jsonpCallback参数时, 相当于向http://127.0.0.1:8008/service/callback=aki&=随机字符串

前端

<script>
    $('.get_service').click(function () {
        $.ajax({
            url: 'http://127.0.0.1:8008/service/',
            type: 'GET',
            dataType: 'jsonp',
            jsonp: 'callback',
            jsonpCallback: 'aki',
            success: function (data) {
            }
        })
    })
</script>

后端

def service(request):
     func = request.GET.get('callbacks')
     info = {'name': 'desky', 'age': 17}
     return HttpResponse("%s('%s')" % func, json.dumps(info))

二  cors跨域

 

后端

def service(request):
    info = {}
    response = HttpResponse(json.dumps(info))
    response["Access-Control-Allow-Origin"] = "*"
    # "*"也可任意指定网址
    return response

前端

正常发ajax就行了

 

 

form表单字段

from django import forms
from django.forms import widgets, fields

下拉框

单选select(initial默认选2)

user = fields.CharField(initial=2, widget=widgets.Select(choices=((1, 'x'), (2, 'a'))))
# user = fields.ChoiceField(choices=(), widget=widgets.Select())

多选select(attrs 给它加属性)

user = fields.MultipleChoiceField(choices=(), widget=widgets.SelectMultiple(attrs={'class': ''}))

 

单选框

user = fields.CharField(widget=widgets.RadioSelect(choices=()))

# user = fields.ChoiceField(choices=(), widget=widgets.RadioSelect)

 

复选框

单选

user = fields.ChoiceField(widget=widgets.CheckboxInput(attrs=()))

多选

user = fields.MultipleChoiceField(choices=(), widget=widgets.CheckboxSelectMultiple)
model 和 Forms对应关系
modelForms
一对多forms.ModelChoiceField
多对多forms.ModelMaltipleChiceField

一对多的type:     <class 'django.forms.model.ModelChoiceField'>

 多对多的type:    <class 'django.forms.model.ModelMultiChoiceField'>

 

判断forn或modelform渲染的字段是不是一对多或多对多

from django.forms.model import ModelChiceField
form = ModelFormDemo()
for bfield in form:
    if istance(bfield.field, ModelChoiceField):
           # 是否一对多字段
        bfield.is_pop = True
          # 对象可以 .xx给它加属性

'''
所以前端可以这样

{% if field.is_pop %}
可以判断是否是一对多, 多对多

'''


print(bfield.field.queryset.model)
# 打印 <class 'app01.model.Publish'>


print(bfield.field.queryset.model._meta.model_name)
# Publish
    

 

form组件的limit_chocie_to={}  

作用于一对多和多对多 

teacher = models.ManyToManyField(..., limit_choice_to = {"depart__in": [1002, 1005]})

相应的也可以在forms中

data = UserInfo.objects.filter(depart__in=[1002, 1005]) .values(''pk", "title")

tracher = forms.ModelMutichoice(choices=data)

 

 

model一些属性

class UserInfo(models.Model):
    username = models.CharField(
        null=True,          # 数据库可以为空
        db_column='user',   # 把数据库默认的username字段改名为user
        max_length=32,
        db_index=True,      # 加速查找
        unique=True,        # 不允许有重复值, 加速查找
    )

    pk = models.ForeignKey(
        to="desky",              # 和哪张表
        to_field='id',           # 和那个字段, 默认时id
        related_name='b',        # 方便反向查找, 反向查找时 .b 就行
        # related_query_name='b',  # 反向查找时, b_set
    )

model的get_字段_display()

class A():
    sex = models.IntegerField(choice=[(1, "男"),(0,"女")])

obj = A.objects.create(name='xx', sex=1)  
print(obj.sex)
# 1
print(obj.get_Sex_display())
# 男

 

mode的Meta:

  1. app_label = 'myapp'             指定模型在哪个app下
  2. table_name = '数据库表的名字'
  3. get_last_by = "order_date"        针对DateField和DateTimeFiel有一个get_last()方法
  4. managed                                    默认是True,为False时不会对数据库进行创建,删除
  5. ording = ['字段升序']   ['-字段降序']
  6. unique_together = (('xx', 'xx'),)
  7. verbose_name = 'xx'                    指定模型的名字
  8. verbose_name_plural = 'xx'          指定模型的复数形式, 不加默认模型名+ s

 

getlist(获取多个值)

request.POST.getlist()

 

CBV

from django.views import View

class AddPublisher(View):
    def get(self, request):
        return ...
    def post(self, request):
        return ...


url
path('xx/', views.AddPublisher.as_view())

 

 

csrf_exempt装饰器

只是关掉了csrf验证

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def teacher..

csrf_protect装饰器

为当前函数设置跨域请求

from django.views.decorators.csrf import csrf_protect

@csrf_protect
def teacher..

 

 

 

url分组匹配

1)url

url(r'^book/([0-9]{2, 4})/ ([a-zA-Z]{2})/$', views.book)

后台(关键字参数)

def book(quest, arg1, arg2):
def book(request, *args):

2) 分组命名匹配

url

url(r'^book/(?P<year>[0-9]{2, 4})/(?P<name>[a-zA-Z]{2})/$', views.book)

后台

def book(request, year, title):
def book(requesr, **kwargs):

 

url 分流

from app01 import url as app01_urls

url(r'^app01/$', include(urls))




app01\urls.py

urlpatterns=[url(r'^book/', xxx)]

当url以app01开头时, 会被分配到app01/urls

 

url的分发匹配

一级分发

# views.py


def test1(request):
def test2(request):
def test3(request):



# urls.py
urlpatterns = [
    path('deskyaki/', ([
        path('test1', test1),
        path('test2', test2),
        path('test3', test3),
    ], None, None))
]

二级分发

urlpatterns = [
    path('deskyaki/', ([
        path('test1/', ([
            path('test4', views.test4),
            path('test05', views.test5),
        ], None, None)),
        path('test2', views.test2)  
    ], None, None))
]

 

多条url访问一个函数(xx/app的名字/表的名字)

urls.py

from django.contrib import admin


def get_urls():
    temp = []
    for model, admin_class_obj in admin.site._registry.items():
        app_name = model._meta.app_label
        model_name = model._meta.model_name
        temp.append(path('{0}/{1}'.format(app_name, model_name), views.test4),)
    return temp




urlpatterns = [
    path('aki/', (get_urls(), None, None), )
]


# 可以访问类似如下的路径http://127.0.0.1:8088/aki/app001/blog

 

模仿admin的url, 实现批量生成app的表的增删改查url

 如 http://127.0.0.1:8088/aki/app001/blog/2/change/

urls.py

from django.urls import path, re_path
from django.contrib import admin
from django.shortcuts import HttpResponse


def list_view(request):
    return HttpResponse('userindex')


def add_view(request):
    return HttpResponse('user_add')


def change_view(request, id):
    return HttpResponse('user_change')


def delete_view(request, id):
    return HttpResponse('user_delete')


def get_urls2():
    temp = []
    temp.append(path('', list_view))
    temp.append(path('/add/', add_view))
    temp.append(re_path(r'/(\d+)/change/', change_view))
    temp.append(re_path(r'/(\d+)/delete/', delete_view))
    return temp


def get_urls():
    temp = []
    for model, admin_class_obj in admin.site._registry.items():
        app_name = model._meta.app_label
        model_name = model._meta.model_name
        temp.append(path('{0}/{1}'.format(app_name, model_name), (get_urls2(), None, None)),)
    return temp


urlpatterns = [
    path('aki/', (get_urls(), None, None), )
]

url 反向解析

1) url

url(r'^xx/$', views.xx, name='fanx_url')

2) 模板

<a href="{% url 'fanx_url' %}"> 点我 </a>

3)后台

def xx(request):
     redirect_url = reverse("fanx_yrl")

当url有参数时

1) url

url(r'^book/(?P<year>[0-9]{2, 4})/(?P<title>[a-zA-Z]{2})/$', views.xx, name='fanx_url')

2) 模板(不管url是分组匹配还是分组命名匹配)

<a href="{% url 'fanx_url' 2018 'xx'}"> 点我 </a>

3) 后台

当url是分组命名匹配时

def xx(request):
    redirect_url = reverse('fanx_url', kwargs={'year': 2018, 'title': 'xx'})

当url时分组匹配时

redirect = reverse('fanx_url', args=[])

url反向解析的命名空间

由于name没有作用域,Django 在反向解析url时,全局搜索,找到第一个name指定url时,立即返回。当我们在app中定义相同的name时,就要用到命名空间。

# app.urls
urlpatters = [
            path('app01/', include('app01.urls', namespance='app01')),
            path('app02/', include('app02.urls', namespance='app02')),
]



# app01.urls
urlpatters = [
            path('index/', index, name='index'),
]


# app02.urls
urlpatters = [
            path('index/', index, name='index'),
]



# views.py
from django.core.urlresovers import reverse

def index(request):
     return HttpResponse(reverse('app01:index'))

 

 

在python脚本中加载dango项目

import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目的名字。settings")
    
import django
django.setup()

from app01 import models
books = models.Book.objects.all()

 

 

 

Django的一些常用方法

1)get() 和 filter()

class Person(models.Model):
    .....
    def __str__(self):
        return self.name

    get()    --->   aki

    fileter()[0]  ---> <Queryset[<person:aki>]>

它们之间的其他区别

1. 输入参数:

get()的参数只是model中定义的些那字段

而filter()的参数可以是字段, 也可以是扩展的, where, in 等

2. 返回值

get()返回的是一个model对象

filter()返回的是一个新的Queryset对象

3. 异常

get()只有一条记录返回时候才正常, 也就说明get的查询字段必须是主键或者是唯一约束字段, 当返回多条记录或者没有找到时会             抛出异常。

filter() 有没有匹配到都不会抛出异常

2) exclude()  排除

ret = models.Person.objects.exclude(id=1)

3) values()

返回一个Queryset对象, 里面类似字典

4)values_list()

返回一个元组

5)order_by()

ret = models.Perosn.objects.all().order_by("-birthday")      加了-表逆序, 不加正常排序

     article_list = models.Article.objects.all().order_by("-weight_art", "-create_time")

            加两个字段, 先按第一个排

6)reverse()      只能将排过序的的逆序

ret = models.Person.objects.all().order_by("xx").reverse()

7) distinct()    

tag_list = models.Tag.objects.values('title').distinct()

8)first(),last()  

9) exists()     Queryset有数据返回True, 没数据返回False

10) count()  计数

11)双下划线

filter(id__lt=10)   

filter(id__gte=1)      大于等于

filter(id__gt=10)   

filter(id__lte=1)      小于等于

filter(id__in=[11, 22, 33])

exclude(id__in=[11, 22, 33])         

filter(name__contains='ven)

filter(name__icontains='ven')     不区分大小写

filter(id__range=[1,3])

models.objects.get(title__regex=r'^(An?|The)+')               匹配正则

models.objects.get(title__iregex=r'^(An?|The)+')              匹配不区分大小写的正则

 

12)only和defer

models.User.objects.all().only('xx', 'xx')                 只取那些字段

models.User.objexts.all().defer('xx', 'xx')               不取哪些字段

13) bulk_create()  批量插入数据

querysetlist = []
for i in resultlist:
    querysetlist.append(Account(name=i))
    # Account是一张表
Account.objects.bulk_create(querysetlist)

14)extra()     执行额外的数据库查询

select:

ret = models.Person.objects.all().extra(select={"gt": "salary > 2000"})

"""
select (salary > 2000) as 'gt', 'person'. 'id', 
'person'.'name', 'person'.'salary', 'person'.'dept_id' from 'persom';
"""
art = models.Article.objects.filter(nid=1).extra(
        select={ "standard_time" : "strftime"('F%%Y-%%m-%%d', create_time)"}).values("standard_time", "nid")

 where:

Person.objects.all().extra(where=["first || last like 'jeffrey %' "])

table:

Book.objects.all().extra(table=['myappp_person'], where=['last=author_last'])

# select * from myapp_book, myapp_person whrere last=author

params:

first_name = 'Joe'
person.objects.all().extra(where=["first='%s'"], params=[first_name])

 

15) select_related()

对于一对一字段和多对一字段,它返回一个Queryset对象,它沿着外键关系查询关联对象,引起性能损耗,但以后使用外键时,则不需要数据库。对于一对多尽量用它,而不是prefetch_related()

class Article(models.Model):
    category = models.Foreignkey('''')
class ArticleDetail(models.Model):
    article = model.OneToOneField(.....)
articleList = model.Article.objects.select_related("category").all()

for article_obj in articleList:
    print(artcle_obj.category.title)

就是顺着Article的外键,找到category的title。

select_related(depath=2)      加这个参数指定深度,不加默认 最大深度。

多外键: model.Article.objects.select_related("category","article").get(nid=1) 或

model.Article.objects.select_related("category").select_related("article")

原理: 相当于联表操作, inner join, 查询次数减少

 

16) prefetch_related()

对于多对多和一对多,查询每个表, 用python处理它们的关系

不使用它的情况

article_obj = models.Article.objects.all()
    for i in article_obj:
        print(i.tags.all())

用它

article_obj = models.Article.objects.prefetch_related("tags").all()
for i in article_obj:
    print(i.tags.all())

 

17)   总结

返回Queryset的

all(), filter(), valuses(). values_list(), exclude(), order_by(), reverse(), distinct()

返回集体对象的

get(), first(), last()

返回布尔值

exists()

返回具体数字

count()

一些小实例

  1. UserInfo.all()                                                                         1. <Queryset [<userInfo:aki>, <UserInfo:desky> ]>
  2. UserInfo.objects()                                                                 2.appoo1.UserInfo.objects
  3. UserInfo.objects.first()                                                          3.aki
  4. UserInfo.objects.all().first()                                                   4.aki
  5. UserInfo.objects.filter(nid=2)                                                5.<Queryset [ <userInfo:desky> ]>
  6. UserInfo.objects.filter(mid=2) .first()                                     6.desky
  7. UserInfo.objects.valuse('nid', 'username')                            7.<Queryset[{'nid': 5, 'username': 'xx'},  {'nid':7,  'username':  'xx'}]>
  8. UserInfo.objects.filter(nid=3).valuse('nid', 'username')         8.<Queryset[{'nid': 5, 'username': 'xx'}}]>
  9. UserInfo.objects.valuse('nid', 'username').filter(nid=3)         9.<Queryset[{'nid': 5, 'username': 'xx'}}]>

 

外键查找

正向(从有外键的一方)

1)双下划线

models.Books.objects.filter(id=1).values("publisher__name")        publisher是Book的外键字段

2)基于对象

book_obj=models.Book.objects.all().first()

ret=book_obj.publisher.name

 

python = models.Book.objects.filter(title='python').first()

ret = python.Publisher.email

 

反向

1)基于对象  (小写表名_set())

pub_obj=models.Publisher.objects.all().first()

pub_obj.book_set().all()

 

pub_obj = models.Publisher.objects.filter(name=xx).first()

pub_obj.book_set().all()

for i in pub_obj:
               print(i.title)

 

2) 基于双下划线

class Book(models.Model):
    ....
    publisher = model,Foreignkey(to='Publisher', on_delete=models.CASCADE, related_name='books')
     # related_name 反向查找的名称

ret=models.Publisher.objects.filter(id=1).values_list('books_title')

 

手动创建第三张表

class Author(models.Model):
    ....
    books = models.ManyToManyField(
        to="Books",                        # 和哪张个表建立多对多关系
        through="Author2Book",             # 通过自己定义的第三张
        through_fields=("author", "book")  # 通过哪些字段, 注意顺序要和第三张表的的字段相同
    )


class Author2Book(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(to='Author')
    book = models.BooleanField(to="Book")

    class Meta:
        unique_together=[('author',"book")]
        # 联合为一

 

分组和聚合 外加 extra() 额外执行查询

聚合

from django.db import models
from django.db.models import Avg, Sum, Max, Min

ret = models.Book.objects.all().aggregate(Avg("price"))
ret = models.Book.objects.all().aggregate(price_avg=Avg("price"))
# 以字典形式返回

分组

from django.db import models

ret = models.Book.objects.all().annotate(author_num=count("author"))
for book in ret:
    print(book.title, book.count.num)


# 查询作者数量大于1的书
ret = models.Book.objects.all().annotate(author_num=count("author").filter(author_num__gt=1))

分组的跨表:(在我看来就是玄学)

ret = models.Person.objects.values("dept_id").annotate(a=Avg('salary')).values("dept__name", "a")

"""
SELECT 'dept'.'name' , Avg('Person', 'salary') As 'a' Form 'Person' INNER JOIN 'dept'
ON ('person', 'dept') group by dept.id
"""

注意: aggregate ----> 字典  , annotate ---->  queryset对象

 

coikie

response = redirect('/xxx/')
response = render(request, 'xx.html')
response.set_cookie('key', 'values')     # 设置cookies 关闭浏览器就失效

# 设置cookies超过10秒失效,写法
response.set_cookie('key','value',max_age=10)

# 从登录10秒后失效,写法
current_time = datetime.datetime.utcnow()
current_data = current_time + datetime.timedelta(seconds=10)
response.set_cookie('key','value',expires=current_data)

response.set_signed_cookie(key,value,salt='加密盐',...)


return response     # 别忘返回



request.COOKIES['key]
request.COOKIES.get('key')


response.delete_cookie('key')

 

session

主要说的存在数据库的session, dango的session默认是存在数据库的, 也就是说使用session之前要提交数据库

request.session['k1']                   # 设置session
 
request.session.get('k1', None)         # 拿session, 拿不到就返回空
request.session['k1'] = 123             # 重置session
request.session.setdefault('k1', 123)   # 存在则不设置


del request.session['k1']               # 删除session

request.session.delete()                # 只删除session
request.session.flush()                 # sesssion 和 cookie 全删


# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()


# 用户session的随机字符串
request.session.session_key

# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
 
# 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key")


request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。

详情

https://www.cnblogs.com/zhuifeng-mayi/p/9099811.html

 

一个js小demo(通过iput失去焦点向后端发送ajax请求, 可以实时看看有没有重名之类的)

my_test.html

里面有两种ajxa跨域方式, 虽然注释掉了一种, 而且ajax的url,不写默认是给自己发ajax。当如果写了类似desky/之类域名,会在自己原来的url基础上加,如自己的url是aki,ajax的url是desky/, 则向aki/desky/发送请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static/jquery-3.3.1.min.js"></script>
    <script src="/static/setupajax.js"></script>

</head>
<body>
<label for="i1">输入框</label>
{#{% csrf_token %}#}
<input type="text" id="i1">

<script>
    $("#i1").blur(function () {
        let $i1Ele=$(this);
        let name=$i1Ele.val();
        {#let csrfToken=$("[name='csrfmiddlewaretoken']").val();#}
        $i1Ele.next("span").remove();
        $.ajax({
            url: '',
            type: "POST",
            dataType: 'JSON',
            {#data: {"name": name, "csrfmiddlewaretoken":csrfToken},#}
            data: {'name': name},
            success: function (arg) {
                let spanEle=document.createElement("span");
                spanEle.innerText=arg;
                $(spanEle).css("color", "red");
                $i1Ele.after(spanEle);
            }
        })
     } )
</script>
</body>
</html>

后端

注意传给前端ajax的arg, 必须是json格式的,Httpresonse要先序列化, 用Jsonresponse如果传的不是字典,要加safe=False参数

def my_ajax(request):
    if request.method == "POST":
        data = request.POST.get('name')
        print(data)
        import json
        a = json.dumps('adc')
        # return HttpResponse(a)
        return JsonResponse('abd', safe=False)
    return render(request, 'my_test.html')

 

中间件

一共有5个,这里只说3个

在app同级下新建my_middleware.py

views.py

def index(request):
    print('我是视图, 自己动')
    return HttpResponse('ojbk')

my_middleware.py

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse


MyURL = ['/']


class OX(MiddlewareMixin):
    def process_request(self, request):
        if request.path_info in MyURL:
            print('这是request中间件')
            return None
        return HttpResponse('被拦住')

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('这是views中间件')
        print(request)
        print(view_func.__name__)
        print(view_args)
        print(view_kwargs)
        return None
        # 返回none继续执行函数 然后执行中间件

        # return HttpResponse('这是中间件的返回值')
        # 不会执行函数,直接跳出,去执行process_response, 如果还有未执行的process_vies则也会直接跳过它们去执行process_response

    def process_response(self, request, response):
        print('这是response中间件')
        # return HttpResponse('ok')
        # Httpresponse覆盖了views的返回
        return response

'''
[03/Jul/2019 17:59:47] "GET / HTTP/1.1" 200 4
这是request中间件
这是views中间件
<WSGIRequest: GET '/'>
index
()
{}
我是视图, 自己动
这是response中间件
<HttpResponse status_code=200, "text/html; charset=utf-8">
'''

千万不要忘了:在settings的MIDDLEWARE中注册, ‘my_middleware.OX’

1) process_request(self, request)

执行顺序: 按照注册顺序,从上到下

返回值:返回None,继续执行; 返回response(Httpresponse)被拦截, 不会继续执行

2)process_response(self, request, response)

执行顺序: 按注册顺序的倒序, 从下到上

返回值: 必须返回response   return response正常执行。 返回 Httpresponse则会覆盖函数的Httpresponse

3) process_views(self, request, view_func, view_args, view_kwargs)

何时执行: 在urls.py找到对应关系后, 在执行视图之前

执行顺序: 按注册顺序, 从上倒下

返回值: 返回None, 继续执行函数和其他中间件; 返回Httpresponse时,不会执行函数和其他的process_views中间件,

不过会接着着执行process_response.

 

上传文件到服务器指定位置

在settings中

# 用户上传文件默认存在这个文件夹下
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

在url中设置,这样就可以通过浏览器访问url看到文件

from django.urls import re_path
from django.views.static import serve
from django.conf import settings




urlpatterns = [
    re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
]

 

Django的密码(把明文密码换成密文)

在Terminal中输入

python manage.py shell

from django.contrib.auth.hashers import make_password

make_password(‘明文密码’)     或者

make_password('明文密码',None, ‘指定加密算法’)

check_password('明文密码', '密文密码')          比较明密密码是否相同, 返回True或False

 

python manage.py shell

from django.contrib.auth.models import User

u = User.objects.get(username='xx')

u.set_password('明文密码')

u.save()

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值