django+drf 前后端分离总结(1)

     阅读:35

django常见问题

django设计模式

django的内置组件

认证组件

auth模块

models
用户模型主要有下面几个字段:username、password、email、first_name、last_name

一般我们继承AbstractUser去扩展

#注意要在setting设置这个、重载系统的用户,让UserProfile生效
AUTH_USER_MODEL = 'users.UserProfile'

authenticate()  
提供了用户认证,即验证用户名以及密码是否正确,一般需要username  password两个关键字参数
        
login(HttpRequest, user)
该函数接受一个HttpRequest对象,以及一个认证了的User对象

此函数使用django的session框架给某个已认证的用户附加上session id等信息

logout(request) 
注销用户
user = authenticate(username='someone',password='somepassword')

from django.contrib.auth import authenticate, login
   
def my_view(request):
  username = request.POST['username']
  password = request.POST['password']
  user = authenticate(username=username, password=password)
  if user is not None:
    login(request, user)
    # Redirect to a success page.
    ...
  else:
    # Return an 'invalid login' error message.
    ...
from django.contrib.auth import logout
   
def logout_view(request):
  logout(request)
  # Redirect to a success page.

缓存

默认缓存

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake'
    }
 }

基于redis的缓存

pip install django-redis

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
            'CONNECTION_POOL_KWARGS': {
                'max_connections': 1000
            },
            # 'PASSWORD': 'xxx', # 如果有设置了redis-server密码在这里设置
        }
    }
}

drf-extensions

pip install drf-extensions

from rest_framework_extensions.cache.mixins import CacheResponseMixin
#CacheResponseMixin一定要放在第一个位置

class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):
setting

#缓存配置
REST_FRAMEWORK_EXTENSIONS = {
    'DEFAULT_CACHE_RESPONSE_TIMEOUT': 5   #5s过期,时间自己可以随便设定
}

自定义cache

django_redis.cache.RedisCache 都是继承了from django.core.cache.backends.base import BaseCache 

继承实现他就可以

FBV缓存举例

# 引入装饰器装饰视图函数即可缓存视图
from django.views.decorators.cache import cache_page

import time
from django.views.decoratosr.cache import cache_page


@chace_page(60*5)  # 必须设置缓存的更新间隔,单位秒
def content_detail(request):
   return HTTPResponse('hello' + str(time.time()))

日志

邮件

email settring中配置

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = False   #是否使用TLS安全传输协议(用于在两个通信应用程序之间提供保密性和数据完整性。)
EMAIL_USE_SSL = True    #是否使用SSL加密,qq企业邮箱要求使用
EMAIL_HOST = 'smtp.163.com'   #发送邮件的邮箱 的 SMTP服务器,这里用了163邮箱
EMAIL_PORT = 25     #发件箱的SMTP服务器端口
EMAIL_HOST_USER = 'charleschen@xmdaren.com'    #发送邮件的邮箱地址
EMAIL_HOST_PASSWORD = '*********'         #发送邮件的邮箱密码(这里使用的是授权码)
from django.core.mail import send_mail  
# send_mail的参数分别是  邮件标题,邮件内容,发件箱(settings.py中设置过的那个),收件箱列表(可以发送给多个人),失败静默(若发送失败,报错提示我们)
send_mail('Subject here', 'Here is the message.', 'charleschen@xmdaren.com',
    ['to@example.com'], fail_silently=False)

分页

Paginator

from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage, InvalidPage
from django.http import HttpResponse
from django.shortcuts import render

def paginator_view(request):
    book_list = []
    '''
    数据通常是从 models 中获取。这里为了方便,直接使用生成器来获取数据。
    '''
    for x in range(1, 26):  # 一共 25 本书
        book_list.append('Book ' + str(x))

    # 将数据按照规定每页显示 10 条, 进行分割
    paginator = Paginator(book_list, 10)

    if request.method == "GET":
        # 获取 url 后面的 page 参数的值, 首页不显示 page 参数, 默认值是 1
        page = request.GET.get('page')
        try:
            books = paginator.page(page)
        # todo: 注意捕获异常
        except PageNotAnInteger:
            # 如果请求的页数不是整数, 返回第一页。
            books = paginator.page(1)
        except InvalidPage:
            # 如果请求的页数不存在, 重定向页面
            return HttpResponse('找不到页面的内容')
        except EmptyPage:
            # 如果请求的页数不在合法的页数范围内,返回结果的最后一页。
            books = paginator.page(paginator.num_pages)

    template_view = 'page.html'
    return render(request, template_view, {'books': books})

静态文件管理

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

# STATIC_ROOT = os.path.join(BASE_DIR, "static/")       #线上设置


、执行python manage.py collectstatic          # 实现静态文件的打包

事物

概念

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

理解:一组sql语句的集合

4 个条件

1. 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样

2. 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

3. 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

4. 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。


常常使用方式

 1 from django.shortcuts import render
 2 from django.http import HttpResponse
 3 from django.views.generic import View
 4 from django.db import transaction   # 导入事务
 5  
 6  
 7 # 类视图 (事务,@transaction.atomic装饰器)
 8 class MyView(View):
 9  
10     @transaction.atomic
11     # transaction.atomic装饰器可以保证该函数中所有的数据库操作都在一个事务中。
12     def post(self, request):
13  
14         # 数据库操作1。。。
15         # 数据库操作2。。。
16         
17         return HttpResponse('ok')
18  
19  
20 # 类视图 (事务,保存点的使用)
21 class MyView2(View):
22     @transaction.atomic
23     def post(self, request):
24  
25         # 设置事务保存点
26         s1 = transaction.savepoint()   # 可以设置多个保存点
27  
28         # 数据库操作。。。
29  
30         # 事务回滚 (如果发生异常,就回滚事务)
31         transaction.savepoint_rollback(s1)  # 可以回滚到指定的保存点
32  
33         # 提交事务 (如果没有异常,就提交事务)
34         transaction.savepoint_commit(s1)
35  
36         # 返回应答
37         return HttpResponse('ok')


比如我们在并发请求经常使用事物进行加锁修改表里的数据

with transaction.atomic():
    task = modelname.objects.select_for_update().get(id=id)
    task.dd = 'cc'
    task.save()

ORM的一些常用方法

返回Queryset方法的API

从数据库中查询出来的结果一般是一个集合,这个集合叫做 QuerySet

1. filter               # 过滤
2. exclude              # 排除
3. annotate             # 聚合
4. order_by             # 排序
5. reverse              # 反向排序
6. distinct             # 去除查询结果中重复的行
7. values               # 迭代时返回字典而不是模型实例对象
8. values_list          # 迭代时返回元祖而不是字典
9. dates                # 表示特定种类的所有可用日期
10. datetimes           # 表示特定种类的所有可用日期
11. all                 # 返回所有结果
12. select_felated      # 外键查询
13. using               # 多个数据库控制QuerySet在那个数据库上求职

ROM中能写sql 语句的方法

1. 使用extra:查询人民邮电出版社出版并且价格大于50元的书籍
Book.objects.filter(publisher__name='人民邮电出版社').extra(where=['price>50']) 

2. 使用raw
books=Book.objects.raw('select * from hello_book')  
for book in books:  
   print book 

3. 自定义sql

from django.db import connection  
  
cursor = connection.cursor()  
cursor.execute("insert into hello_author(name) VALUES ('郭敬明')")  
cursor.execute("update hello_author set name='韩寒' WHERE name='郭敬明'")  
cursor.execute("delete from hello_author where name='韩寒'")  
cursor.execute("select * from hello_author")  
cursor.fetchone()  
cursor.fetchall()

orm高级用法

大于、大于等于

__gt                    # 大于
__gte                   # 大于等于>=

Students.objects.filter(age__gt=10)         //查询年龄大于10的学生
Studnets.objects.filter(age__gte=10)        // 查询年龄大于等于10岁的学生

小于、小于等

__lt                    # 小于<
__lte                   # 小于等于<=

Students.objects.filter(age__lt=10)         //查询年龄小于10岁的学生
Students.objects.filter(age__lte=10)        //查询年龄小于等于10岁的学生

like

__exact                 # 精确等于          //like "aaa"
__iexact                # 精确等于          //忽略大小写 ilike  "aaa"
__contains              # 包含              // like "%aaa"
__icontains             # 包含,忽略大小写  //ilike "aaa",但对于sqlite来说,contains的作用效果等同于icontains


https://www.54371.net/python/django-model-advanced.html

User.objects.filter(Q(state=0) | Q(state=1))

#查找不以z开头并且名称中包含有a或b的书籍
Book.objects.filter(
~ Q(name__startswith='z') &amp; (Q(name__contains='a') | Q(name__contains='b'))

F与Q的作用

F作用:操作数据表中的某列值,F() 允许Django在啊未实际连接数据库的情况下对数据库字段的引用,不能获取对象放在内存中再对字段进行操作,直接执行原生sql语句操作

使用场景:对数据库中的所有的商品,在原价格的基础上涨价10元

from django.db.models import F
from app01.models import Book
Book.objects.update(price=F("price")+20)  # 对于book表中每本书的价格都在原价格的基础上增加20元

Q作用:对对象进行复杂查询,并支持&(and),|(or),~(not)操作符

使用场景:filter查询条件只有一个,而使用Q可以设置多个查询条件

from django.db.models import Q
search_obj=Asset.objects.filter(Q(hostname__icontains=keyword)|Q(ip=keyword))

当同时使用filter的关键字查询和Q查询时,一定要把Q对象放在前面

Asset.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),question__startswith='Who')

批量插入

Entry.objects.bulk_create([
    Entry(headline='This is a test'),
    Entry(headline='This is only a test'),
])

类似于

Entry.objects.create(headline='This is a test')
Entry.objects.create(headline='This is only a test')

Model中ForeignKey字段中的on_delete参数有什么作用

on_delete 有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()

1. CASCADE: 级联删除; 默认值
2. PROTECT: 抛出ProtectedError 以阻止被引用对象的删除,它是django.db.IntegrityError 的一个子类
3. SET_NULL: 把ForeignKey 设置为null; null 参数为True 时才可以这样做
4. SET_DEFAULT: ForeignKey 值设置成它的默认值;此时必须设置ForeignKey 的default 参数
5. SET: 设置ForeignKey 为传递给SET() 的值,如果传递的是一个可调用对象,则为调用后的结果。在大部分情形下,传递一个可调用对象用于避免models.py 在导入时执行查询


Model中怎么ManyToManyField怎么接受删除增加

本质是对中间表的操作

1.models.py中
class Teams(models.Model):
   platformId = models.ManyToManyField(Platform, db_column="platformid", verbose_name=u"平台", help_text='平台',
                                       related_name="platformId", through='RelTeamsPlatform',
                                       through_fields=('teamId', 'platformId'))

class RelTeamsPlatform(models.Model):
   id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, verbose_name=u'编号', help_text=u'编号')
   teamId = models.ForeignKey(Teams, db_column="teamid", help_text=u'team编号', verbose_name=u'team编号',
                              on_delete=models.SET_NULL, null=True, blank=True, related_name='RelTeamsPlatform_teamId')
   platformId = models.ForeignKey(Platform, db_column="platformid", help_text=u'编号', verbose_name=u'编号',
                                  on_delete=models.SET_NULL, null=True, blank=True,
                                  related_name='RelTeamsPlatform_platformId')

class Platform(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, verbose_name=u'编号', help_text=u'编号')

2.serializers.py
class TeamsCreateSerializer(serializers.ModelSerializer):
   createTime = serializers.HiddenField(default=datetime.now)
   createUser = serializers.HiddenField(default=serializers.CurrentUserDefault())
   platformId =serializers.PrimaryKeyRelatedField(many=True, read_only=False, queryset=Platform.objects.all())

   class Meta:
       model = Teams
       exclude = ('modifyUser', 'modifyTime')

   def create(self, validated_data):
       tracks_data = validated_data.pop('platformId') #这里是先把Teams中的platformId
                                                      #这个多对多关系字段剔除出去
                                                      #tracks_data 就是被剔除出去的字段实例结果
       team = Teams.objects.create(**validated_data)  #到这里在创建一个teams实例
       for track_data in tracks_data:
           RelTeamsPlatform.objects.create(teamId=team, platformId=track_data,
                                           createUser=validated_data.get('createUser', None)) 
                                           #到这里是在中间表中把这个关系添加到关系表中
       return team

class TeamsUpdateSerializer(serializers.ModelSerializer):
   platformId = serializers.PrimaryKeyRelatedField(many=True, read_only=False, queryset=Platform.objects.all())

   def update(self, instance, validated_data):
       serializers.raise_errors_on_nested_writes('update', self, validated_data)
       info = model_meta.get_field_info(instance)

       # list(instance.platformId.all()) 是修改前的数据,
       # validated_data['platformId'] 是修改后的数据,前后数据做对比,有改变往下面进行,
       # 没有该表就要
       if list(instance.platformId.all()) != validated_data['platformId']:  #
           tracks_data = validated_data.pop('platformId')
           RelTeamsPlatform.objects.filter(teamId=instance).delete()
           for track_data in tracks_data:
               RelTeamsPlatform.objects.create(teamId=instance, platformId=track_data,
                                               createUser=validated_data.get('modifyUser', None))
       else:
           tracks_data = validated_data.pop('platformId')
       for attr, value in validated_data.items():
           if attr in info.relations and info.relations[attr].to_many:
               field = getattr(instance, attr)
               field.set(value)
           else:
               setattr(instance, attr, value)
       instance.save()
       return instance

djagno 实现websocket

原因:http是对于服务器是被动的,而websocket可以主动发送客户端信息或动作

https://www.jianshu.com/p/3de90e457bb4 https://github.com/jusk9527/websocket