Уведомления

Группа в Telegram: @pythonsu

#1 Июль 27, 2017 08:41:10

vasi.che
Зарегистрирован: 2017-07-27
Сообщения: 19
Репутация: +  0  -
Профиль   Отправить e-mail  

DRF

Коллеги, новичек в 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

Офлайн

#2 Июль 27, 2017 09:03:36

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

DRF

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

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

 ddate = models.DateField(default=date.today())



Офлайн

#3 Июль 27, 2017 09:23:13

vasi.che
Зарегистрирован: 2017-07-27
Сообщения: 19
Репутация: +  0  -
Профиль   Отправить e-mail  

DRF

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

Офлайн

#4 Июль 27, 2017 09:24:42

vasi.che
Зарегистрирован: 2017-07-27
Сообщения: 19
Репутация: +  0  -
Профиль   Отправить e-mail  

DRF

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

ddate = models.DateField(default=date.today())
В двух словах в чем ошибка?

Офлайн

#5 Июль 27, 2017 09:41:42

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

DRF

vasi.che
В двух словах в чем ошибка?
 ddate = models.DateField(default=date.today())
В том, что в терминах джавы ddate - это статический атрибут класса. У объекта есть такой же атрибут, но он не одно и то же. А поскольку атрибут статический, он никогда не изменит значения default. Вы плохо смотрели в документацию, нужно либо сделать default функцией, либо использовать специальный параметр DateField.



Офлайн

#6 Июль 27, 2017 09:45:02

vasi.che
Зарегистрирован: 2017-07-27
Сообщения: 19
Репутация: +  0  -
Профиль   Отправить e-mail  

DRF

FishHook
Понял. Спасибо.

Офлайн

#7 Июль 27, 2017 09:54:40

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

DRF

vasi.che
Если имя контрагента или тип не указан, то подставить значения по умолчанию. Для Contact, если не существует, то создать. Это бизнес-логика.
Джанго - это фреймворк для сайтов, он мало преспособлен для задач энтерпрайза, то есть очень сложная бизнес-логика бывает редко и обычно не выносится в отдельный слой. Логика сознания-изменения объектов БД обычно реализуется в формах https://docs.djangoproject.com/en/1.11/topics/forms/
https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/
и в вашем случае этого было бы вполне достаточно.



Отредактировано FishHook (Июль 27, 2017 09:56:12)

Офлайн

#8 Июль 27, 2017 09:58:55

vasi.che
Зарегистрирован: 2017-07-27
Сообщения: 19
Репутация: +  0  -
Профиль   Отправить e-mail  

DRF

FishHook
А если, допустим, создаете создаете расходную накладную и надо пересчитать остатки и себестоимость, то где размещаете расчет? Или создали заказ и надо послать email?

Офлайн

#9 Июль 27, 2017 10:01:41

vasi.che
Зарегистрирован: 2017-07-27
Сообщения: 19
Репутация: +  0  -
Профиль   Отправить e-mail  

DRF

Судя по документации, прямо в обработчике формы во views.py все-таки

Отредактировано vasi.che (Июль 27, 2017 10:03:41)

Офлайн

#10 Июль 27, 2017 10:19:06

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

DRF

vasi.che
Или создали заказ и надо послать email?
Имейлы отправляются асинхронно, естественно, для этого есть куча расширений, которые реализуют почтовую службу в отдельной процессе.
А если, допустим, создаете создаете расходную накладную и надо пересчитать остатки и себестоимость

Знаете, у меня есть опыт разработки большого проекта на питоне и джанге, я занимаюсь им по сей день и на десять лет вперед работы есть точно. Если бы время отмотать лет на пять назад и если бы спросили моего мнения, я бы никогда не стал рекомендовать джангу для этого проекта. Не потому что она плохая сама по себе, а потому что она не подходит для энтерпрайза. Как только вы начинаете думать над архитектурой, джанга начинает мешать и вы потихоньку запиливаете свой фреймворк. Лучше сразу взять что-нибудь минимальное типа фласка или гибкое типа пирамиды. А еще лучше подобнвми делами на питоне не заниматься, а юзать проверенные решения вроде спринга и радоваться.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version