前言
工作中需要用的一些情况记录。方便学习。
Model
class Scripts(models.Model):
"""
脚本
"""
IS_SYSTEM = [(0, u'自定义'), (1, u'系统内置')]
IS_DELETE = [(0, u'未删除'), (1, u'已删除')]
is_system = models.SmallIntegerField(verbose_name=u"是否系统内置", choices=IS_SYSTEM, default=0)
os_type = models.CharField(verbose_name=u"系统类型唯一标识", max_length=50)
script_type = models.CharField(verbose_name=u"脚本类型", max_length=50)
script_content = models.TextField(verbose_name=u"脚本内容")
is_delete = models.BooleanField(verbose_name=u"是否删除", choices=IS_DELETE, default=False)
class Meta:
db_table = "scripts"
verbose_name = u"脚本"
class Indexes(models.Model):
"""
自定义指标项
"""
IS_CHANGEABLE = [(0, u'不可修改'), (1, u'可修改')]
IS_DELETE = [(0, u'未删除'), (1, u'已删除')]
name = models.CharField(verbose_name=u"指标项名称", max_length=20)
key = models.CharField(verbose_name=u"巡检项字段", max_length=50)
detection_type = models.CharField(verbose_name=u"检测类型唯一标识", max_length=50)
algorithm_method = models.CharField(verbose_name=u"对比方式", max_length=50, null=True)
algorithm_value = models.CharField(verbose_name=u"对比值", max_length=200, null=True)
scripts = models.ForeignKey(Scripts, verbose_name=u"脚本id", null=True)
is_delete = models.BooleanField(verbose_name=u"是否删除", choices=IS_DELETE, default=False)
create_user = models.CharField(verbose_name=u"创建人", max_length=50, null=True)
create_time = models.DateTimeField(verbose_name=u"创建时间", default=datetime.datetime.now)
remark = models.TextField(verbose_name=u"备注", null=True, blank=True)
class Meta:
db_table = "indexes"
verbose_name = u"指标项"
Router
from rest_framework import routers
from apps.indexes import views
router = routers.DefaultRouter(trailing_slash=True)
router.register(r'indexes', views.IndexesModelViewSet, base_name='indexes')
router.register(r'scripts', views.ScriptsViewSet, base_name='scripts')
urlpatterns = router.urls
trailing_slash=True代表url末尾加上’/’,SimpleRouter默认是True。
DefaultRouter比SimpleRouter多一个root api,可以看到类视图集
base_name路由名称前缀。viewset里面queryset不存在,必须写base_name。
ViewSet
class ScriptsViewSet(component_viewsets.ModelViewSet):
serializer_class = ScriptSerializer
queryset = Scripts.objects.all()
class IndexesModelViewSet(component_viewsets.ModelViewSet):
serializer_class = IndexesModelSerializer
queryset = Indexes.objects.filter(is_delete=0)
Serializer
默认的Serializer需要把model对应的字段全部罗列出来
class IndexesSerializer(serializers.Serializer):
name = serializers.CharField(label=u"指标项名称", required=True)
key = serializers.CharField(label=u"巡检项字段", required=False)
...等等
HyperlinkedModelSerializer 会返回url字段,url字段当做主键,而不是id。
ModelSerializer使用简单方便快捷,字段与模型类字段对应
class ScriptSerializer(serializers.ModelSerializer):
class Meta:
model = Scripts
exclude = ('is_delete',)
class IndexesModelSerializer(serializers.ModelSerializer):
scripts = ScriptSerializer(required=False)
class Meta:
model = Indexes
# fields = ['name', 'key']
# 显示所有字段
# fields = '__all__'
# 除了某个字段,其他都显示
exclude = ('is_delete',)
# 查到下一级 ,2代表两级
depth = 1
# 指明只读字段
read_only_fields = ('id', )
validators = [UniqueTogetherValidator(queryset=Indexes.objects.all(),
fields=('name','key'),
message='name和key已经同时存在')]
def create(self, validated_data):
# 重写创建
with transaction.atomic():
script_data = validated_data.pop('scripts')
script = Scripts.objects.create(**script_data)
index = Indexes.objects.create(scripts=script, **validated_data)
return index
def destroy(self, instance):
# 重写删除
instance.is_delete = 1
instance.save()
def update(self, instance, validated_data):
# 重写更新
with transaction.atomic():
# raise_errors_on_nested_writes('update', self, validated_data)
info = model_meta.get_field_info(instance)
# 更新脚本
script_data = validated_data.pop('scripts')
Scripts.objects.update(**script_data)
#
for attr, value in validated_data.items():
if attr in info.relations and info.relations[attr].to_many:
set_many(instance, attr, value)
else:
setattr(instance, attr, value)
instance.save()
return instance
# 添加一个新的字段
def to_representation(self, instance):
data = super(IndexesModelSerializer, self).to_representation(instance)
data['test']='test'
return data
Validate
1、对于单个字段判断是否已存在,序列化器里面加上
name = serializers.CharField(
validators=[UniqueValidator(queryset=Indexes.objects.all(), message=u'name已存在')])
2、对于多个字段判断是否唯一的校验
class Meta:
model = Indexes
exclude = ('is_delete',)
# 对于多个字段判断是否唯一的校验
validators = [UniqueTogetherValidator(queryset=Indexes.objects.all(),
fields=('name','key'),
message='name和key已经同时存在')]
3、对于单个字段的校验
def validate_name(self, value):
import re
pattern = re.compile('[0-9]+')
result = pattern.findall(value)
if not result:
raise serializers.ValidationError(u"name必须包含数字")
return value
4、对于请求数据整体的校验
def validate(self, data):
if data['name']==data['group_key']:
raise serializers.ValidationError(u"name和key不能一样")
return data
Permission
针对视图集所有操作的权限
class IndexesModelViewSet(component_viewsets.ModelViewSet):
serializer_class = IndexesModelSerializer
queryset = Indexes.objects.filter(is_delete=0)
permission_classes = (IsAdmin, )
针对单个操作的权限
@list_route(methods=["DELETE"], permission_classes=(DeletePermission, ))
def test(self, request):
return Response({"test":u"测试"})
class IsAdmin(permissions.BasePermission):
message = u"对不起,您没有该操作的权限,请联系管理员。"
def has_permission(self, request, view):
if request.user.is_superuser:
return True
return False
class DeletePermission(permissions.BasePermission):
"""
删除权限
"""
message = u"您没有删除权限"
def has_permission(self, request, view):
# 对GET方法豁免,存在接口信息越权的问题!
if request.method in permissions.SAFE_METHODS:
return True
if view.action == 'destroy':
# 逻辑处理
return Indexes.objects.filter(id=request.data.get('id')).exists()
return True
has_permission是针对所有对象的权限控制。
has_object_permission针对某一个对象的权限控制。
其他
查询列表功能。不重写list。
需要安装pip install django_filters
from django_filters import rest_framework
class IndexesModelViewSet(component_viewsets.ModelViewSet):
serializer_class = IndexesModelSerializer
queryset = Indexes.objects.filter(is_delete=0)
permission_classes = (IsAdmin, DeletePermission)
filter_backends = (rest_framework.DjangoFilterBackend, )
filter_fields = ("name", )
ok。
自定义分页,统一返回数据格式等可以在上一篇restframework博客中学习到。