Skip to main content
Glama
app.py8.91 kB
// Django Complete Application Template // Save as: app_name/models.py, views.py, serializers.py, urls.py // ============================================ // models.py // ============================================ ` from django.db import models from django.contrib.auth.models import AbstractUser from django.utils import timezone class User(AbstractUser): """Custom user model with additional fields""" email = models.EmailField(unique=True) bio = models.TextField(blank=True) avatar = models.ImageField(upload_to='avatars/', blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] class Meta: ordering = ['-created_at'] def __str__(self): return self.email class Post(models.Model): """Blog post model with full-text search support""" STATUS_CHOICES = [ ('draft', 'Draft'), ('published', 'Published'), ('archived', 'Archived'), ] title = models.CharField(max_length=255) slug = models.SlugField(unique=True, max_length=255) content = models.TextField() excerpt = models.TextField(blank=True) author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts') status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft') featured_image = models.ImageField(upload_to='posts/', blank=True) tags = models.ManyToManyField('Tag', blank=True, related_name='posts') views = models.PositiveIntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) published_at = models.DateTimeField(null=True, blank=True) class Meta: ordering = ['-published_at', '-created_at'] indexes = [ models.Index(fields=['slug']), models.Index(fields=['status', 'published_at']), ] def save(self, *args, **kwargs): if self.status == 'published' and not self.published_at: self.published_at = timezone.now() super().save(*args, **kwargs) def __str__(self): return self.title class Tag(models.Model): """Tag model for categorizing posts""" name = models.CharField(max_length=50, unique=True) slug = models.SlugField(unique=True, max_length=50) def __str__(self): return self.name class Comment(models.Model): """Comment model with threading support""" post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments') author = models.ForeignKey(User, on_delete=models.CASCADE) parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE, related_name='replies') content = models.TextField() is_approved = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['created_at'] def __str__(self): return f'Comment by {self.author} on {self.post}' ` // ============================================ // serializers.py // ============================================ ` from rest_framework import serializers from .models import User, Post, Tag, Comment class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['id', 'email', 'username', 'bio', 'avatar', 'created_at'] read_only_fields = ['created_at'] class UserCreateSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True, min_length=8) class Meta: model = User fields = ['email', 'username', 'password'] def create(self, validated_data): return User.objects.create_user(**validated_data) class TagSerializer(serializers.ModelSerializer): class Meta: model = Tag fields = ['id', 'name', 'slug'] class CommentSerializer(serializers.ModelSerializer): author = UserSerializer(read_only=True) replies = serializers.SerializerMethodField() class Meta: model = Comment fields = ['id', 'author', 'content', 'parent', 'replies', 'created_at'] read_only_fields = ['created_at'] def get_replies(self, obj): if obj.replies.exists(): return CommentSerializer(obj.replies.all(), many=True).data return [] class PostListSerializer(serializers.ModelSerializer): author = UserSerializer(read_only=True) tags = TagSerializer(many=True, read_only=True) class Meta: model = Post fields = ['id', 'title', 'slug', 'excerpt', 'author', 'tags', 'views', 'published_at'] class PostDetailSerializer(serializers.ModelSerializer): author = UserSerializer(read_only=True) tags = TagSerializer(many=True, read_only=True) comments = CommentSerializer(many=True, read_only=True) class Meta: model = Post fields = ['id', 'title', 'slug', 'content', 'excerpt', 'author', 'tags', 'featured_image', 'views', 'comments', 'created_at', 'published_at'] class PostCreateSerializer(serializers.ModelSerializer): tags = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all(), required=False) class Meta: model = Post fields = ['title', 'slug', 'content', 'excerpt', 'tags', 'status', 'featured_image'] def create(self, validated_data): tags = validated_data.pop('tags', []) post = Post.objects.create(**validated_data) post.tags.set(tags) return post ` // ============================================ // views.py // ============================================ ` from rest_framework import viewsets, permissions, status, filters from rest_framework.decorators import action from rest_framework.response import Response from django_filters.rest_framework import DjangoFilterBackend from .models import User, Post, Tag, Comment from .serializers import ( UserSerializer, UserCreateSerializer, PostListSerializer, PostDetailSerializer, PostCreateSerializer, TagSerializer, CommentSerializer ) class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() permission_classes = [permissions.IsAuthenticatedOrReadOnly] def get_serializer_class(self): if self.action == 'create': return UserCreateSerializer return UserSerializer @action(detail=False, methods=['get']) def me(self, request): serializer = UserSerializer(request.user) return Response(serializer.data) class PostViewSet(viewsets.ModelViewSet): queryset = Post.objects.filter(status='published') permission_classes = [permissions.IsAuthenticatedOrReadOnly] filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_fields = ['status', 'author', 'tags'] search_fields = ['title', 'content'] ordering_fields = ['published_at', 'views', 'created_at'] lookup_field = 'slug' def get_serializer_class(self): if self.action == 'list': return PostListSerializer if self.action in ['create', 'update', 'partial_update']: return PostCreateSerializer return PostDetailSerializer def perform_create(self, serializer): serializer.save(author=self.request.user) @action(detail=True, methods=['post']) def increment_views(self, request, slug=None): post = self.get_object() post.views += 1 post.save() return Response({'views': post.views}) class TagViewSet(viewsets.ModelViewSet): queryset = Tag.objects.all() serializer_class = TagSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] lookup_field = 'slug' class CommentViewSet(viewsets.ModelViewSet): serializer_class = CommentSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] def get_queryset(self): return Comment.objects.filter(post__slug=self.kwargs['post_slug'], parent=None) def perform_create(self, serializer): post = Post.objects.get(slug=self.kwargs['post_slug']) serializer.save(author=self.request.user, post=post) ` // ============================================ // urls.py // ============================================ ` from django.urls import path, include from rest_framework.routers import DefaultRouter from rest_framework_nested import routers from . import views router = DefaultRouter() router.register(r'users', views.UserViewSet) router.register(r'posts', views.PostViewSet) router.register(r'tags', views.TagViewSet) # Nested router for comments under posts posts_router = routers.NestedDefaultRouter(router, r'posts', lookup='post') posts_router.register(r'comments', views.CommentViewSet, basename='post-comments') urlpatterns = [ path('', include(router.urls)), path('', include(posts_router.urls)), ] `

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/millsydotdev/Code-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server