验证啊,过滤啊,hypermedia as the engine of ap‐plication state (HATEOAS)啊都有的。
urls.py
__author__ = 'sahara' from rest_framework.routers import DefaultRouter from . import views router = DefaultRouter() router.register(r'sprints', views.SprintViewSet) router.register(r'tasks', views.TaskViewSet) router.register(r'users', views.UserViewset)
models.py
# Create your models here. from django.db import models from django.utils.translation import ugettext_lazy as _ from django.conf import settings class Sprint(models.Model): """Development iteration period.""" name = models.CharField(max_length=100, blank=True, default='') description = models.TextField(blank=True, default='') end = models.DateField(unique=True) def __unicode__(self): return self.name or _('Sprint ending %s') % self.end class Task(models.Model): """Unit of work to be done for the sprint.""" STATUS_TODO = 1 STATUS_IN_PROGRESS = 2 STATUS_TESTING = 3 STATUS_DONE = 4 STATUS_CHOICES = ( (STATUS_TODO, _('Not Started')), (STATUS_IN_PROGRESS, _('In Progress')), (STATUS_TESTING, _('Testing')), (STATUS_DONE, _('Done')), ) name = models.CharField(max_length=100) description = models.TextField(blank=True, default='') sprint = models.ForeignKey(Sprint, blank=True, null=True) status = models.SmallIntegerField(choices=STATUS_CHOICES, default=STATUS_TODO) order = models.SmallIntegerField(default=0) assigned = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True) started = models.DateField(blank=True, null=True) due = models.DateField(blank=True, null=True) completed = models.DateField(blank=True, null=True) def __unicode__(self): return self.name
forms.py
__author__ = 'sahara' import django_filters from .models import Task, Sprint from django.contrib.auth import get_user_model User = get_user_model() class NullFilter(django_filters.BooleanFilter): def filter(self, qs, value): if value is not None: return qs.filter(**{'%s__isnull' % self.name: value}) return qs class TaskFilter(django_filters.FilterSet): backlog = NullFilter(name='sprint') class Meta: model = Task fields = ('sprint', 'status', 'assigned','backlog', ) def __init__(self, *args, **kwargs): super(TaskFilter, self).__init__(*args, **kwargs) self.filters['assigned'].extra.update( {'to_field_name': User.USERNAME_FIELD} ) class SprintFilter(django_filters.FilterSet): end_min = django_filters.DateFilter(name='end', lookup_type='gte') end_max = django_filters.DateFilter(name='end', lookup_type='lte') class Meta: model = Sprint field = ('end_min', 'end_max', )
serializers.py
__author__ = 'sahara' from django.contrib.auth import get_user_model from rest_framework import serializers from rest_framework.reverse import reverse from .models import Sprint, Task from datetime import date from django.utils.translation import ugettext_lazy as _ User = get_user_model() class SprintSerializer(serializers.ModelSerializer): links = serializers.SerializerMethodField() class Meta: model = Sprint fields = ('id', 'name', 'description', 'end', 'links', ) def get_links(self, obj): request = self.context['request'] return { 'self': reverse('sprint-detail', kwargs={'pk': obj.pk}, request=request), 'tasks': reverse('task-list', request=request) + '?sprint={}'.format(obj.pk), } def validate_end(self, attrs): end_date = attrs # new = not self.object #changed = self.object and self.object.end != end_date if (end_date < date.today()): msg = _('End date cannot be in the past.') raise serializers.ValidationError(msg) return attrs class TaskSerializer(serializers.ModelSerializer): assigned = serializers.SlugRelatedField( slug_field=User.USERNAME_FIELD, required=False, read_only=True, ) status_display = serializers.SerializerMethodField() links = serializers.SerializerMethodField() class Meta: model = Task fields = ('id', 'name', 'description', 'sprint', 'status', 'status_display', 'order', 'assigned', 'started', 'due', 'completed', 'links', ) def get_status_display(self, obj): return obj.get_status_display() def get_links(self, obj): request = self.context['request'] links = { 'self': reverse('task-detail', kwargs={'pk': obj.pk}, request=request), 'sprint': None, 'assigned': None, } if obj.sprint_id: links['sprint'] = reverse('sprint-detail', kwargs={'pk': obj.sprint_id}, request=request) if obj.assigned: links['assigned'] = reverse('user-detail', kwargs={User.USERNAME_FIELD: obj.assigned}, request=request) return links def validate_sprint(self, attrs): sprint = attrs if self : pass ''' if sprint != self.sprint: if self.status == Task.STATUS_DONE: msg = _('Cannot change the sprint of a completed task.') raise serializers.ValidationError(msg) if sprint and sprint.end < date.today(): msg = _('Cannot assign task to passed sprint') raise serializers.ValidationError(msg) ''' else: if sprint and sprint.end < date.today(): msg = _('Cannot add tasks to past sprints.') raise serializers.ValidationError(msg) return attrs def validate(self, attrs): sprint = attrs.get('sprint') status = int(attrs.get('status')) started = attrs.get('started') completed = attrs.get('completed') if not sprint and status != Task.STATUS_TODO: msg = _('Backlog tasks must have "Not Started" status.') raise serializers.ValidationError(msg) if started and status == Task.STATUS_TODO: msg = _('Started date cannot be set for not started tasks.') raise serializers.ValidationError(msg) if completed and status != Task.STATUS_DONE: msg = _('Completed date cannot be set for uncompleted tasks.') raise serializers.ValidationError(msg) return attrs class UserSerializer(serializers.ModelSerializer): full_name = serializers.CharField(source='get_full_name', read_only=True) links = serializers.SerializerMethodField() class Meta: model = User fields = ('id', User.USERNAME_FIELD, 'full_name', 'is_active', 'links', ) def get_links(self, obj): request = self.context['request'] user_name = obj.get_username() return { 'self': reverse('user-detail', kwargs={User.USERNAME_FIELD: user_name}, request=request), 'tasks': '{}?assigned={}'.format( reverse('task-list', request=request), user_name), }
views.py
from django.contrib.auth import get_user_model from rest_framework import viewsets, authentication, permissions, filters from .forms import TaskFilter, SprintFilter from .models import Sprint, Task from .serializers import SprintSerializer, TaskSerializer, UserSerializer # Create your views here. User = get_user_model() class DefaultsMixin(object): authentication_classes = ( authentication.BasicAuthentication, authentication.TokenAuthentication, ) permission_classes = ( permissions.IsAuthenticated, ) paginate_by = 25 paginate_by_param = 'page_size' max_paginate_by = 100 filter_backends = ( filters.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter, ) class SprintViewSet(DefaultsMixin, viewsets.ModelViewSet): queryset = Sprint.objects.order_by('end') serializer_class = SprintSerializer filter_class = SprintFilter search_fields = ('name', ) ordering_fields = ('end', 'name', ) class TaskViewSet(DefaultsMixin, viewsets.ModelViewSet): queryset = Task.objects.all() serializer_class = TaskSerializer filter_class = TaskFilter search_fields = ('name', 'description', ) ordering_fields = ('name', 'order', 'started', 'due', 'completed', ) class UserViewset(DefaultsMixin, viewsets.ReadOnlyModelViewSet): lookup_field = User.USERNAME_FIELD lookup_url_kwarg = User.USERNAME_FIELD queryset = User.objects.order_by(User.USERNAME_FIELD) serializer_class = UserSerializer search_fields = (User.USERNAME_FIELD, )
截图,注意有相关链接哟。