From 9db20fb45899d0fd92e075993a623668740ef46d Mon Sep 17 00:00:00 2001 From: Sam Collins Date: Sat, 25 Feb 2017 15:39:57 +0000 Subject: [PATCH] Added Blog and Feeds API --- config/settings/common.py | 32 ++++++++++++++++------------ config/urls.py | 13 ++++++++++-- mhackspace/blog/models.py | 2 ++ mhackspace/blog/serializers.py | 15 +++++++++++++ mhackspace/blog/views.py | 37 ++++++++++++++++++++++++++++++--- mhackspace/feeds/serializers.py | 15 +++++++++++++ mhackspace/feeds/views.py | 19 +++++++++++++++++ requirements/base.txt | 2 ++ 8 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 mhackspace/blog/serializers.py create mode 100644 mhackspace/feeds/serializers.py create mode 100644 mhackspace/feeds/views.py diff --git a/config/settings/common.py b/config/settings/common.py index 924821d..b94ab31 100644 --- a/config/settings/common.py +++ b/config/settings/common.py @@ -28,12 +28,7 @@ DJANGO_APPS = ( 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', - 'stdimage', - - # Useful template tags: - # 'django.contrib.humanize', - - # Admin + 'django.contrib.humanize', 'django.contrib.admin', ) THIRD_PARTY_APPS = ( @@ -41,6 +36,8 @@ THIRD_PARTY_APPS = ( 'allauth', # registration 'allauth.account', # registration 'allauth.socialaccount', # registration + 'stdimage', + 'rest_framework', ) # Apps specific for this project go here. @@ -270,31 +267,30 @@ PAYMENT_PROVIDERS = { 'credentials': { 'merchant_id': env('BRAINTREE_MERCHANT_ID'), 'public_key': env('BRAINTREE_PUBLIC_KEY'), - 'private_key': env('BRAINTREE_PRIVATE_KEY') , + 'private_key': env('BRAINTREE_PRIVATE_KEY'), } }, 'paypal': { - "mode": "sandbox", # sandbox or live + "mode": "sandbox", # sandbox or live 'credentials': { - "mode": "sandbox", # sandbox or live + "mode": "sandbox", # sandbox or live "client_id": env('PAYPAL_CLIENT_ID'), "client_secret": env('PAYPAL_CLIENT_SECRET')} }, - 'gocardless':{ + 'gocardless': { 'environment': 'sandbox', 'credentials': { - 'app_id': env('GOCARDLESS_APP_ID') , + 'app_id': env('GOCARDLESS_APP_ID'), 'app_secret': env('GOCARDLESS_APP_SECRET'), 'access_token': env('GOCARDLESS_ACCESS_TOKEN'), 'merchant_id': env('GOCARDLESS_MERCHANT_ID'), }, - 'redirect_url':'https://test.maidstone-hackspace.org.uk' + 'redirect_url': 'https://test.maidstone-hackspace.org.uk' } } SASS_PRECISION = 8 - SASS_PROCESSOR_INCLUDE_DIRS = [ # str(ROOT_DIR), str(APPS_DIR) + '/static/sass', @@ -306,3 +302,13 @@ SASS_PROCESSOR_ENABLED = True SASS_PROCESSOR_AUTO_INCLUDE = True EMAIL_SUPPORT = 'support@maidstone-hackspace.org.uk' + +REST_FRAMEWORK = { + 'DEFAULT_FILTER_BACKENDS': ( + 'rest_framework.filters.SearchFilter', + 'django_filters.rest_framework.DjangoFilterBackend', + 'rest_framework.filters.OrderingFilter' + ), + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', + 'PAGE_SIZE': 50 +} diff --git a/config/urls.py b/config/urls.py index 6b8ff61..c132e6e 100644 --- a/config/urls.py +++ b/config/urls.py @@ -8,21 +8,30 @@ from django.contrib import admin from django.views.generic import TemplateView from django.views import defaults as default_views from django.contrib.auth import views as auth_views +from rest_framework.routers import DefaultRouter from mhackspace.contact.views import contact from mhackspace.members.views import MemberListView from mhackspace.subscriptions import views as subscription from mhackspace.base.feeds import LatestEntriesFeed from mhackspace.blog.feeds import BlogFeed, BlogCategoryFeed -from mhackspace.blog.views import blog +from mhackspace.blog.views import blog, PostViewSet, CategoryViewSet +from mhackspace.feeds.views import FeedViewSet, ArticleViewSet + +router = DefaultRouter() +router.register(r'posts', PostViewSet) +router.register(r'categories', CategoryViewSet) +router.register(r'feeds', FeedViewSet) +router.register(r'articles', ArticleViewSet) urlpatterns = [ url(r'^$', TemplateView.as_view(template_name='pages/home.html'), name='home'), url(r'^about/$', TemplateView.as_view(template_name='pages/about.html'), name='about'), url(r'^chat/$', TemplateView.as_view(template_name='pages/chat.html'), name='chat'), url(r'^mailing-list/$', TemplateView.as_view(template_name='pages/mailing-list.html'), name='group'), - url(r'^contact/$', contact, name='contact'), + + url(r'^api/v1/', include(router.urls, namespace='v1')), url(r'^blog/$', blog, name='contact'), url(r'^blog/rss/$', BlogFeed()), url(r'^blog/(?P[0-9A-Za-z_\-]+)/$', blog, name='blog-item'), diff --git a/mhackspace/blog/models.py b/mhackspace/blog/models.py index 04712a3..b02b2a9 100644 --- a/mhackspace/blog/models.py +++ b/mhackspace/blog/models.py @@ -6,6 +6,7 @@ from mhackspace.users.models import User from stdimage.models import StdImageField from stdimage.utils import UploadToAutoSlugClassNameDir + class Category(models.Model): name = models.CharField(max_length=100) slug = models.SlugField(max_length=100) @@ -17,6 +18,7 @@ class Category(models.Model): def get_absolute_url(self): return reverse('blog-category', kwargs={'category': self.slug}) + class Post(models.Model): title = models.CharField(max_length=100, unique=True) slug = models.SlugField(max_length=100, unique=True) diff --git a/mhackspace/blog/serializers.py b/mhackspace/blog/serializers.py new file mode 100644 index 0000000..828578e --- /dev/null +++ b/mhackspace/blog/serializers.py @@ -0,0 +1,15 @@ +from rest_framework import serializers + +from mhackspace.blog.models import Post, Category + + +class PostSerializer(serializers.ModelSerializer): + class Meta: + model = Post + fields = ('id', 'title', 'slug', 'categories', 'author', 'image', 'description', 'published_date', 'updated_date') + + +class CategorySerializer(serializers.ModelSerializer): + class Meta: + model = Category + fields = ('id', 'name', 'slug', 'description') diff --git a/mhackspace/blog/views.py b/mhackspace/blog/views.py index be3613a..a019b97 100644 --- a/mhackspace/blog/views.py +++ b/mhackspace/blog/views.py @@ -1,18 +1,24 @@ from django.shortcuts import render from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from rest_framework import filters, viewsets +from django_filters import DateTimeFromToRangeFilter +from django_filters.rest_framework import FilterSet +from django_filters.widgets import RangeWidget from mhackspace.blog.models import Post, Category +from mhackspace.blog.serializers import PostSerializer, CategorySerializer + def blog(request, slug=None, category=None): categories = Category.objects.all() try: if slug is not None: - blog_posts = Post.objects.filter(slug=slug) + blog_posts = Post.objects.filter(active=True, slug=slug) elif category is not None: category = Category.objects.filter(slug=category) - blog_posts = Post.objects.filter(categories=category) + blog_posts = Post.objects.filter(active=True, categories=category) else: - blog_posts = Post.objects.all() + blog_posts = Post.objects.filter(active=True) except Category.DoesNotExist: raise Http404("Category does not exist") except Post.DoesNotExist: @@ -29,3 +35,28 @@ def blog(request, slug=None, category=None): posts = paginator.page(paginator.num_pages) return render(request, 'blog/posts.html', {'posts': posts, 'categories': categories}) + + +class PostFilter(FilterSet): + published_date = DateTimeFromToRangeFilter(widget=RangeWidget(attrs={'placeholder': 'dd/mm/yyyy hh:mm'})) + updated_date = DateTimeFromToRangeFilter(widget=RangeWidget(attrs={'placeholder': 'dd/mm/yyyy hh:mm'})) + + class Meta: + model = Post + fields = ('title', 'slug', 'author__name', 'published_date', 'updated_date') + + +class PostViewSet(viewsets.ModelViewSet): + queryset = Post.objects.filter(active=True) + filter_class = PostFilter + serializer_class = PostSerializer + search_fields = ('title', 'slug', 'categories', 'author__name') + ordering_fields = ('title', 'published_date', 'updated_date', 'author') + + +class CategoryViewSet(viewsets.ModelViewSet): + queryset = Category.objects.all() + serializer_class = CategorySerializer + search_fields = ('name', 'slug') + ordering_fields = ('name', 'slug') + filter_fields = ('name', 'slug') diff --git a/mhackspace/feeds/serializers.py b/mhackspace/feeds/serializers.py new file mode 100644 index 0000000..27d7e0d --- /dev/null +++ b/mhackspace/feeds/serializers.py @@ -0,0 +1,15 @@ +from rest_framework import serializers + +from mhackspace.feeds.models import Feed, Article + + +class FeedSerializer(serializers.ModelSerializer): + class Meta: + model = Feed + fields = ('home_url', 'feed_url', 'title', 'author', 'tags', 'image') + + +class ArticleSerializer(serializers.ModelSerializer): + class Meta: + model = Article + fields = ('url', 'feed', 'original_image', 'image', 'description', 'date') diff --git a/mhackspace/feeds/views.py b/mhackspace/feeds/views.py new file mode 100644 index 0000000..8bbc839 --- /dev/null +++ b/mhackspace/feeds/views.py @@ -0,0 +1,19 @@ +from rest_framework import filters, viewsets +from mhackspace.feeds.models import Feed, Article +from mhackspace.feeds.serializers import FeedSerializer, ArticleSerializer + + +class FeedViewSet(viewsets.ModelViewSet): + queryset = Feed.objects.filter(enabled=True) + serializer_class = FeedSerializer + search_fields = ('home_url', 'feed_url', 'title', 'author__name', 'tags', 'image') + ordering_fields = ('home_url', 'feed_url', 'title', 'author', 'tags', 'image') + filter_fields = ('home_url', 'feed_url', 'title', 'author', 'tags', 'image') + + +class ArticleViewSet(viewsets.ModelViewSet): + queryset = Article.objects.filter(displayed=True) + serializer_class = ArticleSerializer + search_fields = ('url', 'feed__title', 'original_image', 'description', 'date') + ordering_fields = ('url', 'feed', 'date') + filter_fields = ('url', 'feed', 'date') diff --git a/requirements/base.txt b/requirements/base.txt index f104b7d..4a07499 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -58,3 +58,5 @@ braintree==3.35.0 django-autofixture==0.12.1 git+https://github.com/olymk2/scaffold.git +djangorestframework +django-filter