Django可以用LoginRequiredMixin和PermissionRequiredMixin给类视图添加认证和权限,DRF做了高级封装,提供了更简洁的实现方式。我们通过继续学习官网教程来进行了解。
更新model首先修改Snippet模型,添加2个字段:owner,存储snippet创建者,highlighted,存储高亮HTML。同时重写save方法,在同步数据库的时候,使用pygments包把code格式化后存到highlighted字段。修改后的snippets/models.py完整代码如下:
from django.db import models from pygments.lexers import get_all_lexers from pygments.styles import get_all_styles from pygments.lexers import get_lexer_by_name from pygments.formatters.html import HtmlFormatter from pygments import highlight LEXERS = [item for item in get_all_lexers() if item[1]] LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS]) STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()]) class Snippet(models.Model): created = models.DateTimeField(auto_now_add=True) title = models.CharField(max_length=100, blank=True, default='') code = models.TextField() linenos = models.BooleanField(default=False) language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100) style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100) owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE) highlighted = models.TextField() class Meta: ordering = ['created'] def save(self, *args, **kwargs): """ Use the `pygments` library to create a highlighted HTML representation of the code snippet. """ lexer = get_lexer_by_name(self.language) linenos = 'table' if self.linenos else False options = {'title': self.title} if self.title else {} formatter = HtmlFormatter(style=self.style, linenos=linenos, full=True, **options) self.highlighted = highlight(self.code, lexer, formatter) super(Snippet, self).save(*args, **kwargs)接着删除数据库和migrations,重新迁移数据库:
rm -f db.sqlite3 rm -r snippets/migrations python manage.py makemigrations snippets python manage.py migrate并创建超级管理员:
python manage.py createsuperuser User添加EndpointEndpoint,表示API的具体网址。我们按照models.py→serializers.py→views.py→urls.py的代码编写顺序,给User模型添加Endpoint。
models.py
直接使用Django默认User模型,不需要修改代码。
serializers.py
添加UserSerializer,由于User没有snippets字段,所以需要显式添加:
from django.contrib.auth.models import User class UserSerializer(serializers.ModelSerializer): snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all()) class Meta: model = User fields = ['id', 'username', 'snippets']views.py
添加只读的列表视图UserList和详情视图UserDetail,分别用到了ListAPIView和RetrieveAPIView:
from django.contrib.auth.models import User from snippets.serializers import UserSerializer class UserList(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer class UserDetail(generics.RetrieveAPIView): queryset = User.objects.all() serializer_class = UserSerializerurls.py
添加访问路径:
path('users/', views.UserList.as_view()), path('users/<int:pk>/', views.UserDetail.as_view()), 关联User和Snippet如果使用POST方法请求:8000/snippets/,尝试添加1条数据:
会发现接口报错了:
owner_id不能为空?因为前面只给Snippet添加了owner字段,还没有写反序列化更新模型的代码,所以通过请求访问视图,再尝试反序列化的时候,报错了。我们先修改视图SnippetList来修复这个问题:
def perform_create(self, serializer): serializer.save(owner=self.request.user)在SnippetList视图中重写perform_create()方法,意思是在保存时,把request.user值赋给owner字段。perform_create()方法的源码是:
class CreateModelMixin: """ Create a model instance. """ def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): serializer.save()再修改snippets/serializers.py,添加owner字段,支持序列化:
class SnippetSerializer(serializers.ModelSerializer): # ReadOnlyField表示只能序列化为JSON,不能反序列化更新模型 # 也可以改成CharField(read_only=True) owner = serializers.ReadOnlyField(source='owner.username') class Meta: model = Snippet fields = ['id', 'title', 'code', 'linenos', 'language', 'style', 'owner']注意Meta.fields也要加上owner哦。
再请求一次: