Django

                前戏

一.http协议

1.url:协议://域名(IP)+端口(80)/路径?参数(a=1&b=2)

2.基于请求响应

3.基于TCP协议

4.请求协议格式

  请求首行  请求方式 url(路径?get请求参数) 协议/版本号

  请求头   key:value

  请求体   数据(只有post请求才会有请求体)

  User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36

二.Django的下载安装

1.django:pip3 install django == 2.1.1

2.创建Django项目:django-admin.py startproject 项目名称

3.创建应用:python manage.py startapp app名称

4.启动项目:python manage.py runserver IP:PORT

项目名称

  --manage.py   #启动文件   与项目交互命令

  --项目名称

    ----settings.py:配置信息

    ----urls:路径与视图函数的映射

    ----wsgi:封装socket

  app01

    ----models:存放与该app相关的表结构

    ----view:存放与该app相关的视图函数

                正戏

一.url控制器

  urls.py:请求路径与视图函数的映射关系

  (1)简单使用:通过正则分组获取url中的动态参数

  (2)有名分组:给分组起一个名字,实现关键字传参

  (3)分  发:把每一个app自己的url分发各自的路由文件

  (4)反向解析:不要硬编码url,通过别名解析url

二.视图函数

  request(请求对象)

    request.method 请求方式

    request.path 请求路径

    request.POST POST的请求数据,字典格式

    request.GET GET的请求数据,字典格式

    request.META 请求头

    request.get_full_path()

    request.is_ajax()

  request(响应对象)

     三种形式:

      1.HttpResponse("字符串")

      2.render("页面")

        ---读取文件字符串

        ---渲染变量

      3.redirect() #重定向

三.模板语法

服务器发送请求:

  1.地址栏输入url  默认get方式

  2.form表单发请求  可以设置get或post

  3.a标签发请求  

四.ORM(object relation mapping)

    类----------表

类属性-----表字段

类对象-----表记录

 数据库的迁移:django会把setting中的INSTALLED_APPS中每一个应用中models对应类创建成数据库中的表

python manage.py makemigrations   同步

python manage.py migrate

新的数据类型:QuerySet  [obj1,obj2....]

1.添加记录

#方式1:

book=Book(title="python",price=123,pub_date="2012-12-12",publish="人民出版社")
book.save()

#方式2:

book=Book.objects.create(title="python",price=123,pub_date="2012-12-12",publish="人民出版社")

2.查询记录

(1)all(): 调用者:objects管理器   返回queryset

(2)filter(): 调用者:objects管理器  返回queryset

(3)get():  调用者:objects管理器  返回查询到model对象(注意,查询结果有且只有一个才会执行,否则报错)

(4)first(),last()方法: 调用者:queryset  返回model对象

(5)exclude(): 调用者:objects管理器  返回queryset

(6)order_by(): 由queryset对象调用,返回值是queryset

(7)count: 数数: 由queryset对象调用返回int

(8)reverse(): 由queryset对象调用,返回值是queryset

(9)exists(): 由queryset对象调用,返回布尔值

(10)values()方法: 由queryset对象调用,返回值是queryset

(11)values_list(): 由queryset对象调用,返回值是queryset

(12)distinct(): 由queryset对象调用,返回值是queryset

模糊查询(双下划线)

Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100)
Book.objects.filter(price__lt=100)
Book.objects.filter(price__range=[100,200])
Book.objects.filter(title__contains="python")
Book.objects.filter(title__icontains="python")
Book.objects.filter(title__startswith="py")
Book.objects.filter(pub_date__year=2012)

3.删除记录

Book.objects.filter(price=100).delete()

4.修改记录

Book.objects.filter(id=edit_book_id).update(price=111)
Book.objects.filter(price=111).update(publish="南京出版社")

五.ORM的多表操作

1.操作记录

一对多:

  方式1

publish_obj=Publish.objects.get(nid=1)
book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-12-21",price=100,publish=publish_obj)

  方式2:

book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-12-21",price=100,publish_id=1) 
book_obj.publish:与这本书关联出版社对象

多对多操作:

  核心:第三张关系表添加记录

app01_book_author
            id    book_id    author_id
            1         1          1
            2         1          2
            3         2          2
autor
            id      name
            1          liu
            2          wu

  book_obj.author.add(1,2)

  book_obj.author.remove(1)

  book_obj.author.clear()

  book_obj.author.set(3) 清空后设置id

  book_obj.author.all()  查询与这本书关联的所有queryset的集合

2.基于对象的跨表查询(基于子查询)

正向查询

  一对多:

          正向查询按字段:book.publish
Book----------------------------------->Publish
      <-------------------------------------
    反向查询表名小写_set.all():pub_obj,book_set.all()

  多对多:

            正向查询字段book.author.all()
Book------------------------------------->Author
      <----------------------------------------
  反向查询按表名小写_set.all():liu.book_set.all()

  一对一:

                正向查询字段 liu.info
Author------------------------------>AuthorInfo
        <---------------------------------
        反向查询按表名小写  info.author    

  总结:正向查询按字段;反向查询得到一个对象,按表名小写,可能得到多个对象,按表名小写_set().all()

3.基于双下划线的跨表查询(基于join实现的)

创建表结构

from django.db import models
 
 
class Book(models.Model):
    title=models.CharField(max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
 
    # 出版社可以发布多部书(一对多)
    publish=models.ForeignKey('Publish')
 
 
    # 一个人可以写多本书,一本书也可以由多个人撰写(多对多)
    authorList=models.ManyToManyField('Author')
 
class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    addr=models.CharField(max_length=32)
    tel=models.CharField(max_length=13)
 
class Publish(models.Model):
    name=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

编写views代码,查询实现

def index(request):
    bookobj = models.Book.objects.all()
    # 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)
    # ret = models.Book.objects.filter(publish__name='山西出版社').values_list('title')
    # ret = models.Publish.objects.filter(name='山西出版社').values_list('book__title','book__authorList__name')
    # ret = models.Author.objects.filter(book__publish__name='山西出版社').values_list('book__title')
    # 练习2: 查询egon出过的所有书籍的名字(多对多)
    # ret = models.Book.objects.filter(authorList__name='alex').values_list('title')
    # ret =models.Author.objects.filter(name='alex').values_list('book__title')
    # 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名
    # ret = models.Publish.objects.filter(name='机械先驱出版社').values_list('book__title','book__authorList__name')
    # ret = models.Book.objects.filter(publish__name='机械先驱出版社').values_list('title','authorList__name')
    # ret = models.Author.objects.filter(book__publish__name='机械先驱出版社').values_list('book__title','name')
    # 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称
    # ret = models.Author.objects.filter(tel__startswith='158').values_list('book__title','book__publish__name')
    # ret =models.Publish.objects.filter(book__authorList__tel__startswith='158').values_list('book__title','name')
    # ret = models.Book.objects.filter(authorList__tel__startswith='158').values_list('publish__name','title')
    # print(ret)
    return HttpResponse('OK')

六.Ajax

浏览器向服务端发送请求的形式:

1.地址栏输入url 默认get方式

2.form表单的提交按钮 默认get方式

3.a标签 默认get

4.Ajax特点:

  1.异步

  2.局部刷新

$.ajax({
            url:"/cal/",
            type:"post",
            data:{
                num1:num1,
                num2:num2,
                csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()
            },
            success:function(response){
                console.log(reponse);
                $("#ret").val(reponse)
            }
        })
View Code

 json数据

-------------------------------------
| Python         |Json               |
=====================
| dict              |object          |
=====================
| list,tuple       |array            |
=====================
| str                |string         |
=====================
| int,float         |number          |
=====================
| True              |true            |
=====================
| False             |false           |
=====================
| None             |null             |
--------------------------------------

ContentType

  request.POST

  request.GET

  request.body

                     http协议请求格式
            post    url      http
                                  user_agent:.....
                                  accept:...........
                                  ContentType:json
                            user=liu&pwd=123   #封装数据格式:application/x-www-form-urlencoded
                            {"user":"liu","pwd":123} #json格式
浏览器------------------------------------>服务器
        <------------------------------------
                     http协议响应格式
发送接送数据给服务器:
       发送者Ajax:
                       $.ajax({
                            url:"/cal/",
                            type:"post",
                            contentType:"json",
                            data:JSON.stringfy({
                                    num1:num1,
                                    num2:num2,
                                    csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()
                    }),
                            success:function(response){
                                        console.log(response);
                                        $("#ret").val(response)
                  }
             })        

  Django服务器:

      视图函数:json_dict=json.lodas(request.body.decode("utf8"))

  注意:

      Django解析:

if contentType:"urlencoded":
              request.POST=data
elif contentType=="formdata":
              request.FILES=data
else:
               request.POST={}

 七.分页器

假如我们有100本数的数据,想要将其分页,一页展示8条数据

创建数据:
book_list[]
for i in range(100):
      book=Book(title="book_%s"%i,price=i*i)
      book_list.append(book)
Book.objects.bulk_create(list)
分页器的使用:
paginator=Paginator(book_list,8)
print(paginator.count)    #100
print(paginator.num_pages)  #分页数:13
print(paginator.page_range) #range(1,14)

page=paginator.page(5)
for i in page:
    print(i)

print(page.has_next())
print(page.has_previous())
print(page.next_page_number())
print(page.previous_page_number())

  自定义分页

保存搜索条件 保存copy出的数据
QueryDict
    #request.GET["xxx"]=123
    print(type(request.GET))
    from django.http.request import QueryDict
    print(request.GET)
================================================= import copy params=copy.deepcopy(request.GET) params["xxx"]=123 print("params",params) print(params.urlencode()) #"a=1&b=2&xxx=123"

  

 八.cookie与session

cookie:针对每一个服务器都会保存一个key-value结构,类似于{ }

obj=HttpResponse("OK")
obj=render("")
obj=redirect("")
#设置cokkie
obj.set_cookie("key","value","max_age=")
#获取cookie
request.COOKIES.get()
#删除
obj.delete_cookie("cookie_key",path="/",domain=name)

 session

#设置session
request.session["username"]="user"
#取出session
request.session.get("username")
#删除session
del request.session["username"]
request.session.flush()

 用户认证组件

使用django自带的用户表 auth_user
插入记录的命令:python manage.py createsuperuser
1.auth.authenticate(username=user,password=pwd)
2.auth.login(request,user_obj)
    request.session["user_id"]=user.pk
request.user:全局变量,模板,视图直接可以使用
3.auth.logout(request)
4.User.objects.create_user(username=user,password=pwd)
5.#重置密码
   user=User.objects.get(username=request.user.username)
   user.set_password("666")
   user.save()

 九.ModleForm

1.model:

class UserInfo(AbstractUser):
        tel=models.CharField(max_lenght=32)
        gender=models.IntegerField(choices((1,"男"),(2,"女")),default=1)
liu=UserInfo.objects.get(pk=1)
liu.get_gender_display()

2.modelform使用

model.pclass Book(models.Model):

      nid=models.AutoField(primary_key=True)
      title=models.CharField(max_length=32)
      price=models.DecimalField(maax_digits=8,decimal_places=2)
      pub_date=models.DateTimeField()
      publish=models.ForeignKey(to="Publish",on_delete=models.CASCADE)
      authors=models.ManyToManyField(to="Author")
      def __str__(self):
             return self.title

 

form.py:

#构建modelform
class BookModelForm(forms.ModelForm):
        class Meta:
            model=Book
            fields="__all__"

 BookModelForm等同于:

class BookForm(forms.Form):
        title=forms.CharField(max_length=32)
        price=forms.IntegerField()
     pub_date=forms.DateField(widget=widgets.TextInput(attrs={"type":"date"}))
	#publish=forms.ChoiceField(choices=[(1,"AAA"),(2,"BBB")])
	publish=forms.ModelChoiceField(queryset=Publish.objects.all())
	authors=forms.ModelMultipleChoiceField(queryset=Author.objects.all()) 

添加书籍逻辑:

def add(request):
    if method=="GET":
        form=BookModelForm()
        return render(request,"add.html",{"form":form})
    else:
        form=BookModelForm(request.POST)
        if form.is_valid():
            form.save()   #Book.objects.create(**clean_data)
            return redirect("/")
        else:
            return render(request,,"add.html",{"form":form}) 

 编辑书籍逻辑:

def edit(request,id):
    edit_obj=Book.objects.get(pk=id)
    if method=="GET":
        form=BookModelForm(instance=edit_obj)
        return render(request,{"form":form})
    else:
        form=BookModelForm(request.POST,instance=edit_obj)
        if form.is_valid():
            form.save()     #edit_obj.update(clean_data)
            return redirect("/")
        else:
            return render(request,{"form":form})

 十.视图函数

FBV---------function based view

CBV---------class based view

path('index/',Views.index),
path('login/',Views.LoginView.as_view()),
path('login/',View.as_view.view)
#用户访问get请求/login/-------view(request)

十一.自定义过滤器和标签

1.在setting中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.

2.在app中创建templatetages模块(模块名只能是templatetags)

3.创建任意 .py文件,如:my_tags.py

from django import template
from django.utils.safestring import mark_safe
register = template.Library()    #register的名字是固定的,不可变的

@register.filter
def filter_multi(v1,v2):
        return v1*v2

4.在使用自定义simple_tag和filter的html文件导入之前创建的 my_tags.py

{% load my_tags %}

5.使用模板中:

#num = 12
{% load my_tags%}
{{ num|filter_multi:2 }}  #24

总结:

  1.修改表结构:在权限表中加入is_menu和icon两个字段用来表示该权限是否是菜单权限

  2.登录成功后:注入该用户的权限列表和菜单权限列表注入session中

    permission_menu_list = [{},{}]

  3.在菜单区域中(side_bar):渲染出菜单链接标签:

{% for item in request.session.permission_menu_list %}
  <p><a href="{{ item.url }}">{{ item.title }}</a></p>
{% enfor %}

  4.点击标签加入active样式:

    解决思路1:每一个返回模板的视图函数中:

permission_menu_list = request.session.get("permission_menu_list")
for item in permission_menu_list:
        if re.search("^{}$".format(item["url"]),request.path):
            item["class"] = "active"

    解决思路2:引入inclusion_tag方法:

@register.inclusion_tag("rbac/menu.html")
        def get_menu_styles(request):
            permission_menu_list = request.session.get("permission_menu_list")
            for item in permission_menu_list:
                if re.search("^{}$".format(item["url"]),request.path)
                    item["class"] = "active"
            return {"permission_menu_list":permission_menu_list}

  在layout.html中:

<div calss="menu-body">
         {% load web %}
         {% get_menu_styles request %}
</div>
        

十二.rbac(Role-Based Access Control)的应用

(1)先将 rbac 组件移植到新的项目中

(2)将settings中install_app 中加入"rbac"

(3)将新项目的用户表与rbac的User表一对一关联

(4)数据迁移

(5)在登录成功后引入rbac下的initial_session方法,在登录用户的权限信息存储(注意user对象)

(6)在settings中引入rbac下的权限校验中间件

(7)在项目中的base模板中引入菜单样式,渲染显示

原文地址:https://www.cnblogs.com/liuqingyang/p/9488592.html