Найти - Пользователи
Полная версия: DRF
Начало » Django » DRF
1 2 3 4
vasi.che
Коллеги, новичек в Django Rest Framework. Да и вообще в python
Есть ViewSet
 class DocViewSet(viewsets.ModelViewSet):
  queryset = Doc.objects.all()
  serializer_class = DocSerializer
...
  @list_route(methods=['post'])
  def createby(self, request):
    """
   Создание документа по атрибутам
    """
    req = request.data
    ddate = req.get('ddate')
    nameTypeDoc = req.get('typedoc')
    nameContact = req.get('contact')
    comment = req.get('comment')
    doc = Doc.createBy(nameTypeDoc, nameContact, ddate, comment)
    serializer = self.get_serializer(doc)
    return Response(serializer.data)
...

Что не нравится.
1. Из request дергаются атрибуты создаваемого док-та. Ладно. Между получением атрибутов и Doc.create хотелось бы воткнуть валидатор. Валидировать прямо в методе не красиво. Ну допустим:
     ...
    comment = req.get('comment')
    if SomeValidator.isValid(ddate,nameTypeDoc,nameContact,comment):
      doc = Doc.createBy(nameTypeDoc, nameContact, ddate, comment)
    ...

В каком-то другом методе будет другой валидатор. Возникает куча зависимостей от валидаторов.

2. Из ViewSet напрямую дергаю метод модели. В параметрах nameTypeDoc,nameContact. Получается в модель Doc нужно закинуть зависимости TypeDoc и Contact
 class Doc(models.Model):
  """
  Заголовок документа
  """
  n = models.AutoField(primary_key=True)
  typeDoc = models.ForeignKey('TypeDoc', default=1, db_column='typedoc_n')
  ddate = models.DateField(default=date.today())
  contact = models.ForeignKey('Contact', default=1, db_column='contact_n')
...
  @staticmethod
  def createBy(nameTypeDoc=None, nameContact=None, ddate=None, comment=''):
    """
      Создание документа по названию типа и имени контакта
      ddate в формате 'YYYY-mm-dd'
    """
    typeDoc = TypeDoc().getByName(nameTypeDoc)
    contact = Contact().getOrCreate(nameContact)
    if ddate is None:
      _ddate = date.today()
    else:
      d = datetime.strptime(ddate, '%Y-%m-%d')
      _ddate = date(d.year, d.month, d.day)
    doc = Doc(contact=contact, typeDoc=typeDoc, ddate=_ddate, comment=comment)
    doc.save()
    return doc


Ваще не здорово!

3.
 serializer = self.get_serializer(doc)

Для этого метода пусть будет сериализатор по умолчанию. Для другого нужен другой. Можно так:
 class DocViewSetFilter(filters.FilterSet):
    serializer_classes = {
       'createby': DocShortSerializer,
       'get_with_docitems': DocFullSerializer,
Еще один пласт зависимостей.
Че-то как-то жирно.

Получается нужен какой-то слой бизнес-логики DocService , ктр. связывает Doc, Contact, TypeDoc. Зависимости от валидаторов и сериализаторов вроде все-таки остаются тут.

Вообще хотелось бы нечто следующее:
 from models import TypeDoc, Contact, Doc
class DocCreator  :
     
  def createby(params)
    typeDoc = TypeDoc().getByName(nameTypeDoc)
    contact = Contact().getOrCreate(nameContact)
    if ddate is None:
      _ddate = date.today()
    else:
      d = datetime.strptime(ddate, '%Y-%m-%d')
      _ddate = date(d.year, d.month, d.day)
    doc = Doc(contact=contact, typeDoc=typeDoc, ddate=_ddate, comment=comment)
    doc.save()
    return doc
....

В DocViewSet закинуть import DocCreator

Так что-ли? Очень не нравится что класс DocViewSet будет иметь много методов , да еще и с кучей зависимостей. Может через mixin решать? В общем как у вас принято? А вообще хотелось бы какой нибудь типовой проект посмотреть с drf. Но не уровня HelloWorld
FishHook
vasi.che
Много как-то вы всего написали, трудно сразу все охватить. Конкретно с рест-фреймворком я работал мало, но у меня стойкое ощущение, что вы не вполне овладели инструментарием. В частности, вы игнорируете формы джанго, которые собственно и берут на себя всю работу по созданию объектов на основании запроса, поэтому вам и приходится городить велосипед. Полагаю, что вы начали изучение сразу с рест-фреймворка, пропустив саму джангу. Рест-фреймворк, это расширение джанги, а не замена.

ПС. Должен заметить, что так делать нельзя

 ddate = models.DateField(default=date.today())
vasi.che
Да. Вы правы. Я совсем недавно в django. Из java. Мне нужен именно рест. Фронтенды будут разные. Я бы на java написал и не заморачивался, просто есть время. Хочется попробовать альтернативы. Тем более что python все больше нравится. В best-practice советуют использовать толстые модели 10 основных ошибок, совершаемых Django-разработчиками
Но как-то у меня не очень складывается общая схема. В примере выше мне нужно допустим создать док-т. Если имя контрагента или тип не указан, то подставить значения по умолчанию. Для Contact, если не существует, то создать. Это бизнес-логика. Мало того что тащатся зависимости от Contact и TypeDoc, так еще и логика замешивается. Хотя, насколько я понимаю, обязанность модели только работа с БД. Во ViewSet ей (БЛ) тоже как-то не место.
vasi.che
FishHook
ПС. Должен заметить, что так делать нельзя

ddate = models.DateField(default=date.today())
В двух словах в чем ошибка?
FishHook
vasi.che
В двух словах в чем ошибка?
 ddate = models.DateField(default=date.today())
В том, что в терминах джавы ddate - это статический атрибут класса. У объекта есть такой же атрибут, но он не одно и то же. А поскольку атрибут статический, он никогда не изменит значения default. Вы плохо смотрели в документацию, нужно либо сделать default функцией, либо использовать специальный параметр DateField.
vasi.che
FishHook
Понял. Спасибо.
FishHook
vasi.che
Если имя контрагента или тип не указан, то подставить значения по умолчанию. Для Contact, если не существует, то создать. Это бизнес-логика.
Джанго - это фреймворк для сайтов, он мало преспособлен для задач энтерпрайза, то есть очень сложная бизнес-логика бывает редко и обычно не выносится в отдельный слой. Логика сознания-изменения объектов БД обычно реализуется в формах https://docs.djangoproject.com/en/1.11/topics/forms/
https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/
и в вашем случае этого было бы вполне достаточно.
vasi.che
FishHook
А если, допустим, создаете создаете расходную накладную и надо пересчитать остатки и себестоимость, то где размещаете расчет? Или создали заказ и надо послать email?
vasi.che
Судя по документации, прямо в обработчике формы во views.py все-таки
FishHook
vasi.che
Или создали заказ и надо послать email?
Имейлы отправляются асинхронно, естественно, для этого есть куча расширений, которые реализуют почтовую службу в отдельной процессе.
А если, допустим, создаете создаете расходную накладную и надо пересчитать остатки и себестоимость

Знаете, у меня есть опыт разработки большого проекта на питоне и джанге, я занимаюсь им по сей день и на десять лет вперед работы есть точно. Если бы время отмотать лет на пять назад и если бы спросили моего мнения, я бы никогда не стал рекомендовать джангу для этого проекта. Не потому что она плохая сама по себе, а потому что она не подходит для энтерпрайза. Как только вы начинаете думать над архитектурой, джанга начинает мешать и вы потихоньку запиливаете свой фреймворк. Лучше сразу взять что-нибудь минимальное типа фласка или гибкое типа пирамиды. А еще лучше подобнвми делами на питоне не заниматься, а юзать проверенные решения вроде спринга и радоваться.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB