Skip to content
Snippets Groups Projects
Commit e1a349c3 authored by florimondmanca's avatar florimondmanca
Browse files

add document model, api and tests for easy definition of markdown documents

parent 5b2510cd
No related branches found
No related tags found
No related merge requests found
......@@ -7,6 +7,7 @@ from showcase_site import views as showcase_site_views
from tutoring import views as tutoring_views
from users import views as users_views
from visits import views as visits_views
from core import views as core_views
app_name = 'api'
......@@ -45,4 +46,7 @@ router.register('testimonies', showcase_site_views.TestimonyViewSet)
router.register('keyfigures', showcase_site_views.KeyFigureViewSet)
router.register('partners', showcase_site_views.PartnerViewSet)
# Core views
router.register('documents', core_views.DocumentViewSet)
urlpatterns += router.urls
"""Core admin panel configuration."""
from django.contrib import admin
from .models import Document
# Register your models here.
@admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
"""Admin panel for documents."""
list_display = ('title', 'slug',)
readonly_fields = ('slug',)
# reorganize fields
fields = ('title', 'slug', 'content',)
"""Core factories."""
import factory
import factory.django
from . import models
class DocumentFactory(factory.DjangoModelFactory):
"""Document object factory."""
class Meta: # noqa
model = models.Document
title = factory.Faker('sentence', locale='fr')
content = factory.Faker('text', max_nb_chars=1000, locale='fr')
# Generated by Django 2.0.3 on 2018-03-24 18:37
from django.db import migrations, models
import markdownx.models
class Migration(migrations.Migration):
initial = True
dependencies = [
('core', '0002_delete_link'),
]
operations = [
migrations.CreateModel(
name='Document',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(help_text='Titre du document', max_length=300, verbose_name='titre')),
('slug', models.SlugField(help_text='Un court identifiant généré après la création du document.', max_length=100, unique=True)),
('content', markdownx.models.MarkdownxField(help_text='Contenu du document (Markdown est supporté).', verbose_name='contenu')),
],
options={
'ordering': ('title',),
},
),
]
"""Core models."""
from django.shortcuts import reverse
from django.db import models
from django.utils.text import slugify
from markdownx.models import MarkdownxField
class Document(models.Model):
"""Represents a simple document, with a title and a text content.
Markdown support integrated.
"""
title = models.CharField('titre', max_length=300,
help_text="Titre du document")
slug = models.SlugField(
max_length=100, unique=True,
help_text=(
"Un court identifiant généré après la création du document."
))
content = MarkdownxField(
'contenu',
help_text="Contenu du document (Markdown est supporté).")
class Meta: # noqa
ordering = ('title',)
def save(self, *args, **kwargs):
if self.pk is None and not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('api:document-detail', args=[str(self.slug)])
def __str__(self):
return str(self.slug)
from rest_framework import serializers
from .models import Document
from core.markdown import MarkdownField
class DocumentSerializer(serializers.HyperlinkedModelSerializer):
"""Serializer for documents."""
content = MarkdownField()
class Meta: # noqa
model = Document
fields = ('url', 'title', 'slug', 'content')
extra_kwargs = {
# 'slug': {'read_only': True},
'url': {
'view_name': 'api:document-detail',
'lookup_field': 'slug',
},
}
"""Core views."""
from django.shortcuts import get_object_or_404
from rest_framework.mixins import RetrieveModelMixin, ListModelMixin
from rest_framework.viewsets import GenericViewSet
from .models import Document
from .serializers import DocumentSerializer
class DocumentViewSet(RetrieveModelMixin, ListModelMixin, GenericViewSet):
"""API routes that allow to retrieve a document."""
queryset = Document.objects.all()
serializer_class = DocumentSerializer
lookup_field = 'slug'
"""Document API tests."""
from rest_framework import status
from core.factory import DocumentFactory
from core.serializers import DocumentSerializer
from tests.utils import HyperlinkedAPITestCase
class ArticleEndpointsTest(HyperlinkedAPITestCase):
"""Test access to the articles endpoints."""
factory = DocumentFactory
serializer_class = DocumentSerializer
def perform_list(self):
url = '/api/documents/'
response = self.client.get(url)
return response
def test_list_no_authentication_required(self):
self.assertRequestResponse(
self.perform_list,
user=None,
expected_status_code=status.HTTP_200_OK)
def perform_retrieve(self):
obj = self.factory.create()
url = '/api/documents/{obj.slug}/'.format(obj=obj)
response = self.client.get(url)
return response
def test_retrieve_no_authentication_required(self):
self.assertRequestResponse(
self.perform_retrieve,
user=None,
expected_status_code=status.HTTP_200_OK)
"""Document model tests."""
from django.test import TestCase
from core.models import Document
from core.factory import DocumentFactory
from tests.utils import ModelTestCase
class ArticleTest(ModelTestCase):
"""Test the Article model."""
model = Document
field_tests = {
'title': {
'max_length': 300,
'verbose_name': 'titre',
},
'content': {
'verbose_name': 'contenu',
},
'slug': {
'unique': True,
'max_length': 100,
}
}
model_tests = {
'ordering': ('title',),
}
@classmethod
def setUpTestData(cls):
cls.obj = DocumentFactory.create(title='This is a document')
def test_slug_filled_from_title(self):
obj = Document.objects.create(title='This is another document')
self.assertEqual(obj.slug, 'this-is-another-document')
def test_get_absolute_url_from_slug(self):
url = self.obj.get_absolute_url()
expected = '/api/documents/{}/'.format(self.obj.slug)
self.assertEqual(url, expected)
response = self.client.get(url)
self.assertEqual(200, response.status_code)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment