mirror of
https://github.com/pinry/pinry.git
synced 2026-01-26 09:09:30 +01:00
Feature: add basic drf-api for user/pin
This commit is contained in:
117
core/drf_api.py
Normal file
117
core/drf_api.py
Normal 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)
|
||||
@@ -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
42
core/permissions.py
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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')),
|
||||
|
||||
Reference in New Issue
Block a user