記錄一下工做中遇到的問題git
最近在寫restfulframework,感受仍是很便利的django
首先貼一下文檔地址api
https://www.django-rest-framework.org/api-guide/filtering/安全
https://www.django-rest-framework.org/api-guide/serializers/restful
https://www.django-rest-framework.org/api-guide/relations/#manytomanyfields-with-a-through-modelide
使用GernricViewSet能夠便捷的新增接口,在類中定義queryset指定模型,用serializer_class指定序列化類,用pagination_class指定分頁類,再用filter_backends和filter_class作篩選,能夠解決大部分curd問題,以下函數
class GitLabCommit(mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet): #加RetriveModelMixin能夠查詢特定模型的信息 queryset = GitCommit.objects.all() serializer_class = CommitSerializer pagination_class = MyPageNumberPagination filter_backends = (DjangoFilterBackend,) filter_class = UserCommitFilter
其中模型類無需多言,序列化類形以下gitlab
class CommitSerializer(serializers.ModelSerializer): author_email = serializers.CharField(source='author.email') branch_name = serializers.CharField(source = "branch.branchName") branch_project_name = serializers.CharField(source="branch.project.projectName") class Meta: model = GitCommit fields = "__all__"
fields這裏也能夠寫成元組的形式性能
fields = ("StaffId","name","staff_name")
分頁類相似這樣ui
class MyCursorPagination(pagination.CursorPagination): """ Cursor 光標分頁 性能高,安全 """ page_size = 9 ordering = '-update_time' page_size_query_param = "pages" max_page_size = 20 cursor_query_description = '頁面' page_size_query_description = '每頁條數' class MyPageNumberPagination(pagination.PageNumberPagination): """ 普通分頁,數據量越大性能越差 """ page_size = 11 page_size_query_param = 'size' page_query_param = 'page' max_page_size = 20
這是過濾器類,能夠直接定義查找字段或者經過方法進行復雜查找
class UserCommitFilter(filters.FilterSet): user_id = filters.NumberFilter(field_name='author__StaffId', lookup_expr='exact') start_date = filters.DateFilter(field_name='commitDate', lookup_expr='gte') end_date = filters.DateFilter(field_name='commitDate', lookup_expr='lt') commit_sum = filters.NumberFilter(method="get_sum") def get_sum(self,queryset,name,values): if values == 1: return queryset.annotate(total_addLines = Sum("addLines"),total_delLins = Sum("delLines"),total_totalLins = Sum("totalLines"))
這裏有一個問題:若是序列化所涉及的模型是關聯模型怎麼辦呢?
能夠參考這個
https://zhuanlan.zhihu.com/p/27667372
這裏特別說一下,對於多對多模型,能夠經過嵌套來進行關聯,以下
模型定義
class Staff(BaseTable): StaffId = models.IntegerField(primary_key=True, help_text="工號") email = models.CharField(max_length=50,default="",null=True,help_text="郵箱") name = models.CharField(max_length=50,default="",null=True,help_text="姓名") department = models.ForeignKey(Department,on_delete=models.CASCADE) def __str__(self): return "%s:%s"%(self.StaffId,self.name) class Meta: db_table = "gitlab_measure_staff" class GitGroup(BaseTable): id = models.AutoField(primary_key=True, help_text="ID") name = models.CharField(max_length=100,default="",null=True,help_text="組名稱") members = models.ManyToManyField(Staff) class Meta: db_table = "gitlab_measure_gitgroup"
序列化
class StaffSerializer(serializers.ModelSerializer): staff_name = serializers.CharField(source="name") class Meta: model = Staff fields = ("StaffId","name","staff_name") class GitGroupSerializer(serializers.ModelSerializer): members = StaffSerializer(many=True,read_only=True) class Meta: model = GitGroup fields = ("id","name","members")
若是此時又有一個project類中的group關聯到gitgroup,但願在展現的時候展現出組中全部成員該怎麼辦呢?
這裏能夠使用depth指定查詢的深度
class ProjectSerializer(serializers.ModelSerializer): gitGroup_name = serializers.CharField(source='gitGroup.name') gitGroup_id = serializers.CharField(source="gitGroup.id") department_name = serializers.CharField(source="department.name") class Meta: model = GitProject fields = "__all__" depth = 2
這樣在結果中就能看到展現的組和成員了,由於在serilizers.ModelSerializer中的get_field()方法中會根據調用self.build_field,將depth傳入,build_field方法會調用self.buid_nested_field方法來,再返回一個ModelSerializer類,再在外層函數中循環調用來獲取層層對象,最多不超過10層
for field_name in field_names: # If the field is explicitly declared on the class then use that. if field_name in declared_fields: fields[field_name] = declared_fields[field_name] continue extra_field_kwargs = extra_kwargs.get(field_name, {}) source = extra_field_kwargs.get('source', '*') if source == '*': source = field_name # Determine the serializer field class and keyword arguments. field_class, field_kwargs = self.build_field( source, info, model, depth ) # Include any kwargs defined in `Meta.extra_kwargs` field_kwargs = self.include_extra_kwargs( field_kwargs, extra_field_kwargs ) # Create the serializer field. fields[field_name] = field_class(**field_kwargs)
def build_field(self, field_name, info, model_class, nested_depth): """ Return a two tuple of (cls, kwargs) to build a serializer field with. """ if field_name in info.fields_and_pk: model_field = info.fields_and_pk[field_name] return self.build_standard_field(field_name, model_field) elif field_name in info.relations: relation_info = info.relations[field_name] if not nested_depth: return self.build_relational_field(field_name, relation_info) else: return self.build_nested_field(field_name, relation_info, nested_depth) elif hasattr(model_class, field_name): return self.build_property_field(field_name, model_class) elif field_name == self.url_field_name: return self.build_url_field(field_name, model_class) return self.build_unknown_field(field_name, model_class)
def build_nested_field(self, field_name, relation_info, nested_depth): """ Create nested fields for forward and reverse relationships. """ class NestedSerializer(ModelSerializer): class Meta: model = relation_info.related_model depth = nested_depth - 1 fields = '__all__' field_class = NestedSerializer field_kwargs = get_nested_relation_kwargs(relation_info) return field_class, field_kwargs