Django进阶2

一、ORM操作进阶

ForeignKey关联

示例models

from django.db import models
# Create your models here.
class User(models.Model):
    name = models.CharField(max_length=32)

class Host(models.Model):
    host_name = models.CharField(max_length=32)
    blong_to = models.ForeignKey("User")

ForeignKey创建数据

models.Host.objects.create(host_name="127.0.0.1",blong_to=models.User.objects.get(id=1))

1、搜索条件使用 __ 连接  2、获取值时使用 . 连接

user_list=models.Host.objects.filter(blong_to__name="lisi")    #一对多过滤条件

for item in user_list:
    print(item.host_name,item.blong_to.name)  #取数据,在前端取数据也类似

 

ForeignKey修改数据

hosts=models.Host.objects.get(host_name="127.0.0.1")
users=models.User.objects.get(id=2)

hosts.blong_to=users
hosts.save()

反向关联查询

user_obj=models.User.objects.get(id=2)
print(user_obj.host_set.select_related())

 

ManyToManyField关联

示例models

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    address = models.CharField(max_length=128)


class UserGroup(models.Model):
    caption = models.CharField(max_length=64)
    user_info = models.ManyToManyField('UserInfo')

 

ManyToManyField操作(_set是多对多中的固定搭配)

    user_info_obj = models.UserInfo.objects.get(name="zhangsan")
    user_info_objs = models.UserInfo.objects.all()

    group_obj = models.UserGroup.objects.get(caption='CEO')
    group_objs = models.UserGroup.objects.all()

    # 添加数据
    #group_obj.user_info.add(user_info_obj)
    #group_obj.user_info.add(*user_info_objs)
    #
    #user_info_obj.usergroup_set.add(group_obj)
    #user_info_obj.usergroup_set.add(*group_objs)

    # 删除数据
    #group_obj.user_info.remove(user_info_obj)
    #group_obj.user_info.remove(*user_info_objs)
    #
    #user_info_obj.usergroup_set.remove(group_obj)
    #user_info_obj.usergroup_set.remove(*group_objs)

    # 获取数据
    #print group_obj.user_info.all()
    #print group_obj.user_info.all().filter(id=1)
    #
    #print user_info_obj.usergroup_set.all()
    #print user_info_obj.usergroup_set.all().filter(caption='CEO')

 

 F  对同一表内不同的字段进行对比查询

class Entry(models.Model):
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()
from django.db.models import F
models.Entry.objects.filter(n_comments__gt=F('n_pingbacks'))
models.Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)
models.Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))

批量自增

models.Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

 

Q  构建搜索条件

from django.db.models import Q

models.UserInfo.objects.get(
    Q(name='zhangsan'),Q(email="12345678@qq.com"))  #两个都要满足
models.UserInfo.objects.get(
    Q(name='zhangsan') | Q(email="12345678@qq.com"))  #只需满足一个
models.UserInfo.objects.get(
    Q(name='zhangsan'),Q(email="12345678@qq.com") | Q(address="abcde"))

 

django 实现分页

实例

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.shortcuts import render,HttpResponse
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from app01 import models
# Create your views here.
def stu_login(request):
    return render(request,"app01/login.html")


def stu_home(request):
    customer_list=models.Customer.objects.all()
    paginator = Paginator(customer_list, 1) #每页显示条数

    page = request.GET.get('page')
    try:
        contacts = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        contacts = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        contacts = paginator.page(paginator.num_pages)

    return render(request, "app01/home.html", {"customer_list":contacts})
views
    <div class="pagination">
        <nav>
            <ul class="pagination">
                {% if customer_list.has_previous %}
                    <li class=""><a href="?page={{ customer_list.previous_page_number }}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
                {% endif %}
                {% for page_num in customer_list.paginator.page_range %}
                    {% if page_num == customer_list.number %}<!--如果page_num是当前选中的页-->
                      <li class="active"><a href="?page={{ page_num }}">{{ page_num }} <span class="sr-only">(current)</span></a></li>
                    {% else %}
                      <li class=""><a href="?page={{ page_num }}">{{ page_num }} <span class="sr-only">(current)</span></a></li>
                    {% endif %}
                {% endfor %}
                {% if customer_list.has_next %}
                    <li class=""><a href="?page={{ customer_list.next_page_number }}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
                {% endif %}
            </ul>
        </nav>
    </div>
html

 

优化:固定页码个数

1、自定义template tags

  

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import template
from django.utils.safestring import mark_safe

register = template.Library()

@register.simple_tag
def custemer_paging(current_page,loop_num): #传入选中页和循环页
    num_left=current_page-2
    num_right=current_page+2
    if loop_num>num_left and loop_num<num_right:#只显示3页
        if current_page == loop_num:
            result='''<li class="active"><a href="?page=%s">%s <span class="sr-only">(current)</span></a></li>'''%(loop_num,loop_num)
        else:
            result='''<li class=""><a href="?page=%s">%s <span class="sr-only">(current)</span></a></li>'''%(loop_num,loop_num)
        return mark_safe(result)
    result=""
    return mark_safe(result)
custemer_tags.py

 

在html开头导入

{% load custemer_tags %}

 

使用自定义simple_tag

    <div class="pagination">
        <nav>
            <ul class="pagination">
                {% if customer_list.has_previous %}
                    <li class=""><a href="?page={{ customer_list.previous_page_number }}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
                {% endif %}
                {% for page_num in customer_list.paginator.page_range %}
                    
                    {% custemer_paging customer_list.number page_num %}<!--使用custemer_tags-->

                {% endfor %}
                {% if customer_list.has_next %}
                    <li class=""><a href="?page={{ customer_list.next_page_number }}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
                {% endif %}
            </ul>
        </nav>
    </div>
View Code

 

更多详情:https://docs.djangoproject.com/en/1.9/topics/pagination/ 

 

三、在自己写的脚本里调用django models

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'django_project.settings'
import django
django.setup()

from app01 import models

result = models.UserInfo.objects.get(id=1)
print(result)
View Code

 

四、用户认证

from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    name = models.CharField(max_length=32)

 

from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.decorators import login_required

@login_required
def acc_home(request):
    return render(request,"index.html")

def acc_login(request):
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        user = authenticate(username=username,password=password) #验证

        if user is not None:
            login(request,user) #登录
            return redirect("/app01/acc_home/")
    else:
        return render(request,"login.html")

def acc_logout(request):
    logout(request) #退出

在前端显示用户名或对应的名字

    <div>
        {% if request.user.is_authenticated %} <!--如果已经登录-->
            <span>{{ request.user }}</span> <!--用户名-->
            <span>{{ request.user.userprofile.name }}</span> <!--用户名在UserProfile表对应的名字-->
        {% endif %}
    </div>

五、权限管理

django 自带有基本的权限管理 ,但粒度和限制权限的维度都只是针对具体的表

自己写的权限要易扩展、灵活,权限系统的设计对开发者、用户要实现透明,即他们不需要改变自己原有的使用系统或调用接口的方式,权限要能实现非常小的粒度的控制,甚至细致到一个按键某个用户是否能按。

想对一个功能实现权限控制,要做到只需在views方法上加一个装饰器就行了

例:

在表内创建一个class Meta,自己定义几个权限。

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    name = models.CharField(verbose_name=u"姓名",max_length=32)
    def __unicode__(self):
        return self.name
    class Meta:
        permissions = (("view_customer_list",u"查看客户信息"),
                       ("view_customer_info",u"查看客户详细信息"),
                       ("view_customer_updata",u"修改详细信息"),
                       )

python manage.py makemigrations
python manage.py migrate

关联动作

这里创建一个permissions.py,创建check_permission装饰器

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from django.core.urlresolvers import resolve
 4 from django.shortcuts import render
 5 perm_dic = {
 6     "view_customer_list":["customer_list","GET",[]],
 7     "view_customer_info":["customer_info","GET",[]],
 8     "view_customer_updata":["customer_info","POST",[]],
 9 }
10 
11 
12 def perm_check(*args,**kwargs):
13      request = args[0]
14      url_resovle_obj = resolve(request.path_info)
15      current_url_namespace = url_resovle_obj.url_name
16      #app_name = url_resovle_obj.app_name #use this name later
17      print("url namespace:",current_url_namespace)
18      matched_flag = False # find matched perm item
19      matched_perm_key = None
20      if current_url_namespace is not None:#if didn't set the url namespace, permission doesn't work
21          print("find perm...")
22          for perm_key in perm_dic:
23              perm_val = perm_dic[perm_key]
24              if len(perm_val) == 3:#otherwise invalid perm data format
25                  url_namespace,request_method,request_args = perm_val
26                  print(url_namespace,current_url_namespace)
27                  if url_namespace == current_url_namespace: #matched the url
28                      if request.method == request_method:#matched request method
29                          if not request_args:#if empty , pass
30                              matched_flag = True
31                              matched_perm_key = perm_key
32                              print('mtched...')
33                              break #no need looking for  other perms
34                          else:
35                              for request_arg in request_args: #might has many args
36                                  request_method_func = getattr(request,request_method) #get or post mostly
37                                  #print("----->>>",request_method_func.get(request_arg))
38                                  if request_method_func.get(request_arg) is not None:
39                                      matched_flag = True # the arg in set in perm item must be provided in request data
40                                  else:
41                                      matched_flag = False
42                                      print("request arg [%s] not matched" % request_arg)
43                                      break #no need go further
44                              if matched_flag == True: # means passed permission check ,no need check others
45                                  print("--passed permission check--")
46                                  matched_perm_key = perm_key
47                                  break
48 
49      else:#permission doesn't work
50          return True
51 
52      if matched_flag == True:
53          #pass permission check
54          perm_str = "app01.%s" %(matched_perm_key)
55          if request.user.has_perm(perm_str):
56              print("\033[42;1m--------passed permission check----\033[0m")
57              return True
58          else:
59              print("\033[41;1m ----- no permission ----\033[0m")
60              print(request.user,perm_str)
61              return False
62      else:
63          print("\033[41;1m ----- no matched permission  ----\033[0m")
64 
65 def check_permission(func):
66      def wrapper(*args,**kwargs):
67          print("---start check perms",args[0])
68          if not perm_check(*args,**kwargs):
69              return render(args[0],'app01/403.html')
70          return func(*args,**kwargs)
71          #print("---done check perms")
72      return wrapper
permissions.py
    url(r'^stu_home/$', views.stu_home,name="customer_list"),
    url(r'^stu_detail/(\d+)/$', views.stu_detail,name="customer_info"),

 

在views导入自己写的装饰器并在相应方法上加一个装饰器

可以用超级用户通过admin对普通用户进行权限控制

 

六、CSRF(跨站域请求伪造)

CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一

 防御策略

  在请求地址中添加 token 并验证

Django 中使用CSRF,在表单下使用{% csrf_token %}

<form action="" method="post">{% csrf_token %}

  

AJAX中CSRF

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);
        }
    }
});

 

posted @ 2016-06-17 11:41  J_hong  阅读(533)  评论(0编辑  收藏  举报