Skip to content

Commit

Permalink
chore: add ruff to lint and format python code
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelovicentegc committed Jun 25, 2024
1 parent 21525de commit ff63a04
Show file tree
Hide file tree
Showing 44 changed files with 560 additions and 379 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ coverage
.ionide

# IntelliJ
.idea
.idea

# Ruff
.ruff_cache
7 changes: 7 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
echo "Running static tests..."
pnpm run test:static
echo "Done running static tests."

echo "Formatting code..."
pnpm run format
echo "Done formatting code."
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# django-react-typescript <!-- omit from toc -->

<img alt="django-react-typescript logo" src="assets/Logo.png" align="right" width="95" height="95" />
<img alt="django-react-typescript logo" src="assets/Logo.png" align="right" width="120" height="120" />

This is an non-opinionated Django 5 + React 18 boilerplate built with great development experience and easy deployment in mind.

Expand Down
2 changes: 1 addition & 1 deletion api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@


class ApiConfig(AppConfig):
name = 'api'
name = "api"
7 changes: 4 additions & 3 deletions api/filters/publications.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from django_filters import rest_framework as filters
from backend.models.publications import Publication


class PublicationFilter(filters.FilterSet):
tag = filters.CharFilter(field_name='tag', lookup_expr='icontains')
title = filters.CharFilter(field_name='title', lookup_expr='icontains')
tag = filters.CharFilter(field_name="tag", lookup_expr="icontains")
title = filters.CharFilter(field_name="title", lookup_expr="icontains")

class Meta:
model = Publication
fields = ['title', 'tag']
fields = ["title", "tag"]
2 changes: 0 additions & 2 deletions api/serializers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
from .publications import PublicationsSerializer
from .subscribers import SubscribersSerializer
14 changes: 12 additions & 2 deletions api/serializers/publications.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
from rest_framework import serializers
from backend.models.publications import Publication


class PublicationsSerializer(serializers.ModelSerializer):
image = serializers.SerializerMethodField(read_only=True)

def get_image(self, instance):
return instance.image.url

class Meta:
model = Publication
fields = ('title', 'slug', 'description', 'body', 'image', 'tag', 'image_description', 'created_at')
model = Publication
fields = (
"title",
"slug",
"description",
"body",
"image",
"tag",
"image_description",
"created_at",
)
3 changes: 2 additions & 1 deletion api/serializers/subscribers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from rest_framework import serializers
from backend.models.subscribers import Subscriber


class SubscribersSerializer(serializers.ModelSerializer):
class Meta:
model = Subscriber
fields = ('name', 'contact_method', 'contact_info')
fields = ("name", "contact_method", "contact_info")
3 changes: 0 additions & 3 deletions api/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
from django.test import TestCase

# Create your tests here.
24 changes: 15 additions & 9 deletions api/urls.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
from django.urls import re_path
from rest_framework.authtoken.views import obtain_auth_token
from .views.subscribers import SubscribersEndpoint
from .views.publications import PublicationsEndpoint, PublicationsQueryEndpoint, PaginatedPublicationsQueryEndpoint, PaginatedPublicationsEndpoint, PublicationEndpoint
from .views.publications import (
PublicationsEndpoint,
PublicationsQueryEndpoint,
PaginatedPublicationsQueryEndpoint,
PaginatedPublicationsEndpoint,
PublicationEndpoint,
)


urlpatterns = [
re_path(r'^subscribers/$', SubscribersEndpoint.as_view() ),
re_path(r'^publications/p/$', PaginatedPublicationsEndpoint.as_view() ),
re_path(r'^publications/filter/$', PublicationsQueryEndpoint.as_view() ),
re_path(r'^publications/p/filter/$', PaginatedPublicationsQueryEndpoint.as_view()),
re_path(r'^publications/(?P<slug>[\w\-]+)/$', PublicationEndpoint.as_view()),
re_path(r'^publications/$', PublicationsEndpoint.as_view() ),
re_path(r'^authenticate/$', obtain_auth_token)
]
re_path(r"^subscribers/$", SubscribersEndpoint.as_view()),
re_path(r"^publications/p/$", PaginatedPublicationsEndpoint.as_view()),
re_path(r"^publications/filter/$", PublicationsQueryEndpoint.as_view()),
re_path(r"^publications/p/filter/$", PaginatedPublicationsQueryEndpoint.as_view()),
re_path(r"^publications/(?P<slug>[\w\-]+)/$", PublicationEndpoint.as_view()),
re_path(r"^publications/$", PublicationsEndpoint.as_view()),
re_path(r"^authenticate/$", obtain_auth_token),
]
23 changes: 14 additions & 9 deletions api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@
from rest_framework.response import Response
from collections import OrderedDict


class Pagination(PageNumberPagination):
page_size = 9
page_size_query_params = 'page_size'
page_size_query_params = "page_size"
max_page_size = 100

def get_paginated_response(self, data):
return Response(OrderedDict([
('count', self.page.paginator.count),
('current_page', self.page.number),
('total_pages', self.page.paginator.num_pages),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data)
]))
return Response(
OrderedDict(
[
("count", self.page.paginator.count),
("current_page", self.page.number),
("total_pages", self.page.paginator.num_pages),
("next", self.get_next_link()),
("previous", self.get_previous_link()),
("results", data),
]
)
)
28 changes: 16 additions & 12 deletions api/views/publications.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
from rest_framework import generics, filters
from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from backend.models.publications import Publication
from api.filters.publications import PublicationFilter
from api.serializers.publications import PublicationsSerializer
from api.utils import Pagination
from rest_framework.permissions import IsAuthenticated
from rest_framework.permissions import IsAuthenticated


class PaginatedPublicationsEndpoint(generics.ListAPIView):
permission_classes = (IsAuthenticated,)
queryset = Publication.objects.all()
serializer_class = PublicationsSerializer
pagination_class = Pagination


class PublicationsEndpoint(generics.ListAPIView):
permission_classes = (IsAuthenticated,)
queryset = Publication.objects.all()
serializer_class = PublicationsSerializer


class PublicationsQueryEndpoint(generics.ListAPIView):
permission_classes = (IsAuthenticated,)
queryset = Publication.objects.all()
serializer_class = PublicationsSerializer
filter_backends = [DjangoFilterBackend]
filterset_class = PublicationFilter


class PaginatedPublicationsQueryEndpoint(generics.ListAPIView):
permission_classes = (IsAuthenticated,)
queryset = Publication.objects.all()
Expand All @@ -34,27 +38,27 @@ class PaginatedPublicationsQueryEndpoint(generics.ListAPIView):
filterset_class = PublicationFilter
pagination_class = Pagination


class PublicationEndpoint(APIView):
permission_classes = (IsAuthenticated,)


def get(self, request, format=None, **kwargs):
"""
Returns the a publication by its slug.
"""

try:
publication = Publication.objects.get(slug=kwargs.get('slug'))
publication = Publication.objects.get(slug=kwargs.get("slug"))

formatted_publication = {
'title': publication.title,
'description': publication.description,
'created_at': publication.created_at,
'slug': publication.slug,
'body': publication.body,
'image': publication.image.url,
"title": publication.title,
"description": publication.description,
"created_at": publication.created_at,
"slug": publication.slug,
"body": publication.body,
"image": publication.image.url,
}

return Response(formatted_publication)
except Publication.DoesNotExist:
return Response("This publication doesn't exist yet.")
return Response("This publication doesn't exist yet.")
12 changes: 6 additions & 6 deletions api/views/subscribers.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
from backend.models.subscribers import Subscriber
from api.serializers.subscribers import SubscribersSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.permissions import IsAuthenticated


class SubscribersEndpoint(APIView):
"""
Interface for users to send their subscription data.
"""

permission_classes = (IsAuthenticated,)

def post(self,request):
def post(self, request):
serializer = SubscribersSerializer(data=request.data)

if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_201_CREATED)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
2 changes: 1 addition & 1 deletion backend/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
default_app_config = 'backend.apps.BackendConfig'
default_app_config = "backend.apps.BackendConfig"
10 changes: 5 additions & 5 deletions backend/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@


class ExportCsvMixin:
def export_as_csv(self, request, queryset):
def export_as_csv(self, _, queryset):
meta = self.model._meta
field_names = [field.name for field in meta.fields]

response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename={}.csv'.format(meta)
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = "attachment; filename={}.csv".format(meta)
writer = csv.writer(response)

writer.writerow(field_names)
for obj in queryset:
row = writer.writerow([getattr(obj, field) for field in field_names])
writer.writerow([getattr(obj, field) for field in field_names])

return response

export_as_csv.short_description = "Export selected to CSV"
export_as_csv.short_description = "Export selected to CSV"
2 changes: 0 additions & 2 deletions backend/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
from .publications import PublicationAdmin
from .subscribers import SubscriberAdmin
31 changes: 16 additions & 15 deletions backend/admin/publications.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,29 @@
from django.utils.html import format_html
from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin
from backend.models.publications import Publication
from backend.actions import ExportCsvMixin
from backend.utils import Strings


@admin.register(Publication)
class PublicationAdmin(admin.ModelAdmin, DynamicArrayMixin):
def image_preview(self, obj):
return format_html('<img src="{}" style="height: 150px" />'.format(obj.image.url))

image_preview.short_description = Strings.IMAGE
return format_html(
'<img src="{}" style="height: 150px" />'.format(obj.image.url)
)

list_filter = ('created_at',)
list_display = ('title', 'image_preview', 'created_at')
readonly_fields = ['slug']
image_preview.short_description = Strings.IMAGE

list_filter = ("created_at",)
list_display = ("title", "image_preview", "created_at")
readonly_fields = ["slug"]

fieldsets = (
(None, {
'fields': ('title', 'slug', 'body', 'image', 'tag')
}),
(Strings.OPTIONAL_FIELDS, {
'classes': ('collapse',),
'fields': ('description', 'image_description'),
}),
(None, {"fields": ("title", "slug", "body", "image", "tag")}),
(
Strings.OPTIONAL_FIELDS,
{
"classes": ("collapse",),
"fields": ("description", "image_description"),
},
),
)

10 changes: 5 additions & 5 deletions backend/admin/subscribers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

@admin.register(Subscriber)
class SubscriberAdmin(admin.ModelAdmin, ExportCsvMixin):
list_filter = ('contact_method', 'created_at')
list_filter = ("contact_method", "created_at")
actions = ["export_as_csv"]
search_fields = ['name']
list_display = ('name', 'contact_info', 'created_at')
readonly_fields = ['name', 'contact_info', 'contact_method']
search_fields = ["name"]
list_display = ("name", "contact_info", "created_at")
readonly_fields = ["name", "contact_info", "contact_method"]

class Media:
js = ('backend/subscribers.js',)
js = ("backend/subscribers.js",)
6 changes: 3 additions & 3 deletions backend/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@


class BackendConfig(AppConfig):
name = 'backend'
verbose_name = 'Public website'
name = "backend"
verbose_name = "Public website"

def ready(self):
import backend.signals
return
3 changes: 2 additions & 1 deletion backend/management/commands/clearcache.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django.core.management.base import BaseCommand
from django.core.cache import cache


class Command(BaseCommand):
def handle(self, *args, **kwargs):
cache.clear()
self.stdout.write('Cleared cache\n')
self.stdout.write("Cleared cache\n")
Loading

0 comments on commit ff63a04

Please sign in to comment.