- ModelViewSet jest zazwyczaj spoko w większości przypadków.
To generowanie automatyczne frontendu, to nie kwestia użycia modelviewsetu a drfa, on sobie ogólnie generuje taki froncik pomocny. To raz.
Testowanie jedynie przez przeklikiwanie jest złe. Pisz testy i koniec.
Tam gdzie potrzebujesz sztampowego ModelViewSeta, używaj go. Tam, gdzie jakieś mocno Customowe rzeczy, możesz ApiView. Tam gdzie tylko np. niektóre metody to po prostu rzeczy typu generics.ListCreateAPIView
. Patrz czego ci potrzeba.
- W serializerze raczej te funkcje, które dotyczą walidacji/serializacji danych. W widoku te, odpowiedzialne za ich prezentacje/responsa. W modelu jakies constarainty na fieldach itd + rzeczy które dotyczą samego modelu.
Pisz dokumentacje: czy to autogenerowaną np. drf swagger generatorem jakimś, czy też ręcznie swaggera.
Trzymaj się jakiś konkrentych guidelinów - jednolicie pisz to api. Jakiś spec typu https://jsonapi.org. Do teog warto poczytać chociaż by zalando api guidelines.
Używaj raczej Routera z drfa.
To takie pierwsze rzeczy, które przychodzą mi do głowy.
Bardzo fajnie to napisałeś.
Od siebie chciałem zapytać o podejście do pewnego typu problemu.
Otóż, zdarzyło mi się stworzyć korpo aplikację typu: Cheklista,
trochę taki excel z pytaniami i odpowiedziami w stylu True/False, historią zmian i tworzeniem szablonów).
Właśnie kiedy w osobnej JS-owej aplikacji na froncie tworzę taki szablon nowej Checklisty, to wysyłam JSON-a do API w Django Rest Frameworku.
Mam dwie koncepcje.
podejście 1.
W np. ModelViewSet jechać pętlami po kolejnych zagnieżdżeniach tego JSON-a i odpalać kolejne serializery i zapisywać do bazy.
W tym podejściu mam (wydaje się) pełną kontrolę nad tym jak serializuję takiego JSON-a. Czy tworzę nowe obiekty w bazie, czy np. dodaje tylko nowe powiązania (np. jedno pytanie może należeć do wielu Checklist, itp.)
plusy:
- łatwy dostęp do danych z sesji
minusy:
podejście 2.
JSON powinien być tak przygotowany (w pełni serializowalny), że wrzucam go Od razu w pierwszy serializer od Checklisty i dalej "automat" Django Rest Frameworku.
Tutaj wydaje mi się, że trochę tracę kontrolę nad tym jak serializowane są kolejne stopnie zagnieżdżenia takiego JSON-a, choć... można to obejść poprzez grzebanie w odpowiednich serializerach.
plusy:
- ładny i czytelny kod warstwy prezentacji
minusy:
- czasami bałagan z serializerami (przynajmniej ja czasami potrzebowałem tworzyć po 2-3 serializery dla jednego modelu, w zależności czy chciałem go odczytać czy zapisać)
- trudny dostęp do danych sesji, parametrów zapytania w request, itp.
Może jest jakaś trzecia droga? Poradnik/Tutorial jak zapisywać rozbudowane relacje przez DRF? Ja znajdywałem zwykle tutoriale pokazujące bardzo proste przypadki.
PS. Aplikacja powstała, działa, podoba się "użyszkodnikom", tylko jak ja patrzę w kod, to widzę że można było lepiej i stąd to raczej luźne pytanie. Jeśli potrzeba to dostarczę jakiś pseudokod :)
EDIT: Doklejam kodzik:
from django.db import models
class Template(models.Model):
"""
Used for preparing new Checklist.
Allows to fully edit content and order of question rows and columns.
Answers for questions can be set as "default answer".
"""
name = models.CharField(max_length=100)
class FeatureChecklist(models.Model):
"""
Used for storing answers for question provided by users.
Only answers are fully editable, order of questions and columns is fixed.
"""
name = models.CharField(max_length=100)
class Checklist(models.Model):
"""
Used by Template as well as FeatureChecklist as "storage"
for question rows and columns.
"""
# Relation to Template model
template = models.OneToOneField('Template',
on_delete=models.CASCADE,
related_name='checklist',
default=None,
blank=True,
null=True)
feature_checklist = models.OneToOneField('FeatureChecklist',
on_delete=models.CASCADE,
related_name='checklist',
default=None,
blank=True,
null=True)
def save(self, *args, **kwargs):
"""
Prevent Checklist against having two owners from Template or FeatureChecklist.
"""
if self.template and self.feature_checklist:
raise ValueError("Checklist can have only one owner: "
"One of fields 'template' or 'feature_checklist' "
"must be None.")
else:
return super().save(*args, **kwargs)
class QuestionColumn(models.Model):
"""
Holds column names for related Checklist object.
"""
name = models.CharField(max_length=100)
column_order = models.IntegerField()
# Relation to Checklist model
checklist = models.ForeignKey('Checklist', null=True, blank=True, related_name='question_columns')
class QuestionRow(models.Model):
"""
Holds question names for related Checklist object.
"""
name = models.TextField() # Question text should be stored
row_order = models.IntegerField()
# Relation to Checklist model
checklist = models.ForeignKey('Checklist', null=True, blank=True, related_name="question_rows")
class AnswerCell(models.Model):
"""
Like a cell in Excel. It has relation QuestionColumn and QuestionRow
"""
value = models.TextField()
question_column = models.ForeignKey('QuestionColumn', on_delete=models.CASCADE, related_name="answer_cells")
question_row = models.ForeignKey('QuestionRow', on_delete=models.CASCADE, related_name="answer_cells")
example_Template_JSON_from_FrontEnd = {
"name": "Test Template",
"checklist": {
"question_column": [
{
"name": "QuestionColumn1",
"column_order": 1
},
{
"name": "QuestionColumn2",
"column_order": 2
},
{
"name": "QuestionColumn3",
"column_order": 3
},
],
"question_row": [
{
"name": "QuestionRow1",
"row_order": 1
},
{
"name": "QuestionRow2",
"row_order": 2
},
{
"name": "QuestionRow3",
"row_order": 3
},
],
"answer_cells": [
{
"value": "AnswerCell11",
"column_order": 1,
"row_order": 1,
},
{
"value": "AnswerCell21",
"column_order": 2,
"row_order": 1,
},
{
"value": "AnswerCell31",
"column_order": 3,
"row_order": 1,
},
# :
# :
# etc.
]
}
}
Rezultat to trochę bardziej interaktywne to:
Chodzi o to, że właściwie wszystkie obiekty są dopiero tworzone z tego JSON-a na końcu kodu (brak PK)
I np. aby zapisać Checklistę muszę najpierw zapisać Template i pozykać Template PK. Zatem po kolei jadę pętlą FOR i wypakowuję kolejne...
Czy to złe? :)