验证啊,过滤啊,hypermedia as the engine of ap‐plication state (HATEOAS)啊都有的。
urls.py
__author__ = 'sahara'from rest_framework.routers import DefaultRouterfrom . import viewsrouter = 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 modelsfrom django.utils.translation import ugettext_lazy as _from django.conf import settingsclass 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.endclass 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_filtersfrom .models import Task, Sprintfrom django.contrib.auth import get_user_modelUser = 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 qsclass 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_modelfrom rest_framework import serializersfrom rest_framework.reverse import reversefrom .models import Sprint, Taskfrom datetime import datefrom 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 attrsclass 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 attrsclass 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_modelfrom rest_framework import viewsets, authentication, permissions, filtersfrom .forms import TaskFilter, SprintFilterfrom .models import Sprint, Taskfrom .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, )
截图,注意有相关链接哟。