Skip to content

Commit 1e27e65

Browse files
Merge pull request #5 from Wackerbarth/Transition
Transition
2 parents 87cf4c5 + 81e29bf commit 1e27e65

8 files changed

Lines changed: 90 additions & 71 deletions

File tree

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
*.pyc
1+
# Database content will be handled by fixtures
22
*.db
3+
4+
# These are normally defined globally
5+
*.pyc
36
*~
47
.*
58

9+
# Accept these files in the repository
610
!.gitignore
711
!.travis.yml

snippets/fixtures/initial_data.json

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,73 @@
11
[
22
{
3-
"pk": 2,
4-
"model": "auth.user",
3+
"pk": 2,
4+
"model": "auth.user",
55
"fields": {
6-
"username": "aziz",
7-
"first_name": "",
8-
"last_name": "",
9-
"is_active": true,
10-
"is_superuser": false,
11-
"is_staff": false,
12-
"last_login": "2012-10-28T21:36:57.799Z",
13-
"groups": [],
14-
"user_permissions": [],
15-
"password": "pbkdf2_sha256$10000$2x3LOiFCb9sq$3jiN4zgb3wYHQ9fpn/elUrcn1S1Bq/q0djZFBjb8Y2w=",
16-
"email": "",
6+
"username": "aziz",
7+
"first_name": "",
8+
"last_name": "",
9+
"is_active": true,
10+
"is_superuser": false,
11+
"is_staff": false,
12+
"last_login": "2012-10-28T21:36:57.799Z",
13+
"groups": [],
14+
"user_permissions": [],
15+
"password": "pbkdf2_sha256$10000$2x3LOiFCb9sq$3jiN4zgb3wYHQ9fpn/elUrcn1S1Bq/q0djZFBjb8Y2w=",
16+
"email": "",
1717
"date_joined": "2012-10-28T21:36:57.799Z"
1818
}
19-
},
19+
},
2020
{
21-
"pk": 3,
22-
"model": "auth.user",
21+
"pk": 3,
22+
"model": "auth.user",
2323
"fields": {
24-
"username": "amy",
25-
"first_name": "",
26-
"last_name": "",
27-
"is_active": true,
28-
"is_superuser": false,
29-
"is_staff": false,
30-
"last_login": "2012-10-28T21:42:34.081Z",
31-
"groups": [],
32-
"user_permissions": [],
33-
"password": "pbkdf2_sha256$10000$wjy2WvTgw1Ro$oR8pVFHIBqZUmD9XEHdRl5m4TxWOF+qnvZn/q+npTlc=",
34-
"email": "",
24+
"username": "amy",
25+
"first_name": "",
26+
"last_name": "",
27+
"is_active": true,
28+
"is_superuser": false,
29+
"is_staff": false,
30+
"last_login": "2012-10-28T21:42:34.081Z",
31+
"groups": [],
32+
"user_permissions": [],
33+
"password": "pbkdf2_sha256$10000$wjy2WvTgw1Ro$oR8pVFHIBqZUmD9XEHdRl5m4TxWOF+qnvZn/q+npTlc=",
34+
"email": "",
3535
"date_joined": "2012-10-28T21:42:34.081Z"
3636
}
37-
},
37+
},
3838
{
39-
"pk": 4,
40-
"model": "auth.user",
39+
"pk": 4,
40+
"model": "auth.user",
4141
"fields": {
42-
"username": "max",
43-
"first_name": "",
44-
"last_name": "",
45-
"is_active": true,
46-
"is_superuser": false,
47-
"is_staff": false,
48-
"last_login": "2012-10-28T21:42:45.711Z",
49-
"groups": [],
50-
"user_permissions": [],
51-
"password": "pbkdf2_sha256$10000$NhDNt8GNYfjC$0FlcsJxt8Sac0dvGv+xcaUVSUfh1UYZfWEq3C1WoHjc=",
52-
"email": "",
42+
"username": "max",
43+
"first_name": "",
44+
"last_name": "",
45+
"is_active": true,
46+
"is_superuser": false,
47+
"is_staff": false,
48+
"last_login": "2012-10-28T21:42:45.711Z",
49+
"groups": [],
50+
"user_permissions": [],
51+
"password": "pbkdf2_sha256$10000$NhDNt8GNYfjC$0FlcsJxt8Sac0dvGv+xcaUVSUfh1UYZfWEq3C1WoHjc=",
52+
"email": "",
5353
"date_joined": "2012-10-28T21:42:45.711Z"
5454
}
55-
},
55+
},
5656
{
57-
"pk": 5,
58-
"model": "auth.user",
57+
"pk": 5,
58+
"model": "auth.user",
5959
"fields": {
60-
"username": "jose",
61-
"first_name": "",
62-
"last_name": "",
63-
"is_active": true,
64-
"is_superuser": false,
65-
"is_staff": false,
66-
"last_login": "2012-10-28T21:43:03.591Z",
67-
"groups": [],
68-
"user_permissions": [],
69-
"password": "pbkdf2_sha256$10000$ibnHXtPQKwBN$Kab9tTROT6bpxnAI1imgb0kdlAmBuAQ5Z0fAzHbkL68=",
70-
"email": "",
60+
"username": "jose",
61+
"first_name": "",
62+
"last_name": "",
63+
"is_active": true,
64+
"is_superuser": false,
65+
"is_staff": false,
66+
"last_login": "2012-10-28T21:43:03.591Z",
67+
"groups": [],
68+
"user_permissions": [],
69+
"password": "pbkdf2_sha256$10000$ibnHXtPQKwBN$Kab9tTROT6bpxnAI1imgb0kdlAmBuAQ5Z0fAzHbkL68=",
70+
"email": "",
7171
"date_joined": "2012-10-28T21:43:03.591Z"
7272
}
7373
}

snippets/models.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
from django.db import models
2-
from pygments.lexers import get_all_lexers, get_lexer_by_name
2+
from pygments.lexers import get_all_lexers
33
from pygments.styles import get_all_styles
4+
from pygments.lexers import get_lexer_by_name
45
from pygments.formatters import HtmlFormatter
56
from pygments import highlight
67

78
LEXERS = [item for item in get_all_lexers() if item[1]]
89
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
910
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
1011

11-
1212
class Snippet(models.Model):
1313
created = models.DateTimeField(auto_now_add=True)
1414
title = models.CharField(max_length=100, default='')
@@ -27,6 +27,10 @@ class Meta:
2727
ordering = ('created',)
2828

2929
def save(self, *args, **kwargs):
30+
"""
31+
Use the `pygments` library to create a highlighted HTML
32+
representation of the code snippet.
33+
"""
3034
lexer = get_lexer_by_name(self.language)
3135
linenos = self.linenos and 'table' or False
3236
options = self.title and {'title': self.title} or {}
@@ -35,7 +39,7 @@ def save(self, *args, **kwargs):
3539
self.highlighted = highlight(self.code, lexer, formatter)
3640
super(Snippet, self).save(*args, **kwargs)
3741

38-
# maximize the amount of instances to be created
42+
# limit the number of instances retained
3943
snippets = Snippet.objects.all()
4044
if len(snippets) > 100:
4145
snippets[0].delete()

snippets/permissions.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
from rest_framework import permissions
22

3-
43
class IsOwnerOrReadOnly(permissions.BasePermission):
4+
"""
5+
Custom permission to only allow owners of an object to edit it.
6+
"""
7+
58
def has_permission(self, request, view, obj=None):
9+
# Skip the check unless this is an object-level test
610
if obj is None:
711
return True
812

13+
# Read permissions are allowed to any request
914
if request.method in permissions.SAFE_METHODS:
1015
return True
1116

17+
# Write permissions are only allowed to the owner of the snippet
1218
return obj.owner == request.user

snippets/serializers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1+
from rest_framework import serializers
12
from snippets.models import Snippet
23
from django.contrib.auth.models import User
3-
from rest_framework import serializers
4-
54

65
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
76
owner = serializers.Field(source='owner.username')

snippets/views.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
from rest_framework import generics, permissions, renderers
1+
from django.contrib.auth.models import User
2+
from rest_framework import generics
3+
from rest_framework import permissions
4+
from rest_framework import renderers
25
from rest_framework.decorators import api_view
36
from rest_framework.response import Response
47
from rest_framework.reverse import reverse
5-
from django.contrib.auth.models import User
68
from snippets.models import Snippet
79
from snippets.permissions import IsOwnerOrReadOnly
810
from snippets.serializers import SnippetSerializer, UserSerializer
911

10-
1112
@api_view(('GET',))
1213
def api_root(request, format=None):
1314
"""
@@ -48,7 +49,7 @@ def pre_save(self, obj):
4849
obj.owner = self.request.user
4950

5051

51-
class SnippetInstance(generics.RetrieveUpdateDestroyAPIView):
52+
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
5253
"""
5354
This view presents an instance of a code snippet.
5455
@@ -62,7 +63,8 @@ class SnippetInstance(generics.RetrieveUpdateDestroyAPIView):
6263
"""
6364
model = Snippet
6465
serializer_class = SnippetSerializer
65-
permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)
66+
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
67+
IsOwnerOrReadOnly,)
6668

6769
def pre_save(self, obj):
6870
obj.owner = self.request.user

tutorial/settings.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
DATABASES = {
1313
'default': {
14-
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
15-
'NAME': 'tmp.db', # Or path to database file if using sqlite3.
14+
'ENGINE': 'django.db.backends.sqlite3', # Or use an alternate database backend.
15+
'NAME': 'tmp.db', # Path to sqlite3 database file.
1616
'USER': '', # Not used with sqlite3.
1717
'PASSWORD': '', # Not used with sqlite3.
1818
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
@@ -115,8 +115,12 @@
115115
'django.contrib.sites',
116116
'django.contrib.messages',
117117
'django.contrib.staticfiles',
118-
'snippets',
118+
# Uncomment the next line to enable the admin:
119+
# 'django.contrib.admin',
120+
# Uncomment the next line to enable admin documentation:
121+
# 'django.contrib.admindocs',
119122
'rest_framework',
123+
'snippets',
120124
)
121125

122126
# A sample logging configuration. The only tangible logging

tutorial/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
urlpatterns = format_suffix_patterns(patterns('snippets.views',
66
url(r'^$', 'api_root'),
77
url(r'^snippets/$', views.SnippetList.as_view(), name='snippet-list'),
8-
url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetInstance.as_view(), name='snippet-detail'),
8+
url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view(), name='snippet-detail'),
99
url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view(), name='snippet-highlight'),
1010
url(r'^users/$', views.UserList.as_view(), name='user-list'),
1111
url(r'^users/(?P<pk>[0-9]+)/$', views.UserInstance.as_view(), name='user-detail')

0 commit comments

Comments
 (0)