Feature: add basic drf-api for user/pin

This commit is contained in:
winkidney
2019-02-19 18:57:36 +08:00
parent 50ffa93d46
commit 220c49a725
6 changed files with 203 additions and 1 deletions

117
core/drf_api.py Normal file
View File

@@ -0,0 +1,117 @@
from rest_framework import serializers, viewsets, routers
from taggit.models import Tag
from core.models import Image, Pin
from core.permissions import IsOwnerOrReadOnly
from django_images.models import Thumbnail
from django.conf import settings
from users.models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = (
'username',
'gravatar',
'url',
)
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class ThumbnailSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Thumbnail
fields = (
"image",
"width",
"height",
)
class ImageSerializer(serializers.ModelSerializer):
class Meta:
model = Image
fields = (
"image",
"width",
"height",
"standard",
"thumbnail",
"square",
)
standard = ThumbnailSerializer(read_only=True)
thumbnail = ThumbnailSerializer(read_only=True)
square = ThumbnailSerializer(read_only=True)
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ("name", )
class PinSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Pin
fields = (
settings.DRF_URL_FIELD_NAME,
"id",
"submitter",
"url",
"origin",
"description",
"referer",
"image",
"tags",
)
tags = serializers.SlugRelatedField(
many=True,
source="tag_list",
queryset=Tag.objects.all(),
slug_field="name",
)
image = ImageSerializer(required=False)
def create(self, validated_data):
image_file = validated_data.pop('image')
if validated_data['url']:
image = Image.objects.create_for_url(
validated_data['url'],
validated_data['referer'],
)
else:
image = Image.objects.create(image=image_file['image'])
pin = Pin.objects.create(image=image, **validated_data)
tags = validated_data.pop('tag_list')
if tags:
pin.tags.set(*tags)
return pin
def update(self, instance, validated_data):
tags = validated_data.pop('tag_list')
if tags:
instance.tags.set(*tags)
image_file = validated_data.pop('image', None)
if image_file:
image = Image.objects.create(image=image_file['image'])
instance.image = image
return super(PinSerializer, self).update(instance, validated_data)
class PinViewSet(viewsets.ModelViewSet):
queryset = Pin.objects.all()
serializer_class = PinSerializer
filter_fields = ('submitter__username', )
permission_classes = [IsOwnerOrReadOnly("submitter"), ]
drf_router = routers.DefaultRouter()
drf_router.register(r'users', UserViewSet)
drf_router.register(r'pins', PinViewSet)

View File

@@ -43,9 +43,32 @@ class ImageManager(models.Manager):
class Image(BaseImage):
objects = ImageManager()
class Sizes:
standard = "standard"
thumbnail = "thumbnail"
square = "square"
class Meta:
proxy = True
@property
def standard(self):
return Thumbnail.objects.get(
original=self, size=self.Sizes.standard
)
@property
def thumbnail(self):
return Thumbnail.objects.get(
original=self, size=self.Sizes.thumbnail
)
@property
def square(self):
return Thumbnail.objects.get(
original=self, size=self.Sizes.square
)
class Pin(models.Model):
submitter = models.ForeignKey(User)
@@ -57,6 +80,9 @@ class Pin(models.Model):
published = models.DateTimeField(auto_now_add=True)
tags = TaggableManager()
def tag_list(self):
return self.tags.all()
def __unicode__(self):
return '%s - %s' % (self.submitter, self.published)

42
core/permissions.py Normal file
View File

@@ -0,0 +1,42 @@
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.IsAuthenticatedOrReadOnly):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def __init__(self, owner_field_name="owner"):
self.__owner_field_name = owner_field_name
def __call__(self):
return self
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
return getattr(obj, self.__owner_field_name) == request.user
class OwnerOnly(permissions.IsAuthenticatedOrReadOnly):
def has_permission(self, request, view):
return request.user.is_authenticated()
def has_object_permission(self, request, view, obj):
return obj.owner == request.user
class SuperUserOnly(permissions.BasePermission):
"""
The request is authenticated as a user, or is a read-only request.
"""
def has_permission(self, request, view):
return request.user.is_superuser
def has_object_permission(self, request, view, obj):
return request.user.is_superuser

View File

@@ -3,6 +3,7 @@ from django.views.generic import TemplateView
from tastypie.api import Api
from core.drf_api import drf_router
from .api import ImageResource, ThumbnailResource, PinResource, UserResource
from .views import CreateImage

View File

@@ -15,6 +15,7 @@ INSTALLED_APPS = [
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'django_filters',
'taggit',
'compressor',
'django_images',
@@ -142,10 +143,17 @@ IS_TEST = False
IMAGE_AUTO_DELETE = True
# Rest Framework
DRF_URL_FIELD_NAME = "resource_link"
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
],
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
),
'URL_FIELD_NAME': DRF_URL_FIELD_NAME,
}

View File

@@ -4,10 +4,18 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.contrib import admin
from django.views.static import serve
from core.drf_api import drf_router
admin.autodiscover()
urlpatterns = [
# drf api
url(r'^drf_api/', include(drf_router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace="rest_framework")),
# old api and views
url(r'^admin/', include(admin.site.urls)),
url(r'', include('core.urls', namespace='core')),
url(r'', include('users.urls', namespace='users')),