Django в стартапе: от 0 до 150 000 строк кода, не жертвуя качеством

Django в стартапе: от 0 до 150 000 строк кода, не жертвуя качеством

Фёдор Борщёв (ГдеМатериал) @ Moscow Python № 72
"Речь пойдет о том, как мы поддерживаем здоровье кодовой базы в проекте с безумными требованиями к скорости и постоянно меняющимися задачами. Мы поговорим про TDD, SOLID и KISS там, где люди меньше всего к этому готовы — в стартапе, который доставляет стройматериалы".

Видео: http://www.moscowpython.ru/meetup/72/django-in-startup/

53b0434aded1fb944ec3037c382158c1?s=128

Moscow Python Meetup

January 30, 2020
Tweet

Transcript

  1. 2.
  2. 3.
  3. 6.
  4. 14.
  5. 17.
  6. 18.

    Traefik: Понятный синтаксис, автосертификаты deploy: replicas: 2 labels: - "traefik.enable=true"

    - "traefik.port=8000" - "traefik.frontend.rule=Host:app.gdml.ru; PathPrefix:/api/,/admin/" - "traefik.docker.network=traefiknet"
  7. 20.
  8. 24.

    Тестировать ручки API def test_create_with_author(api, author): api.post('/api/v1/leads/', { 'customer': {'phone':

    '+7 999 999-99-99'}, 'author': author.id, }) got = Lead.objects.last() assert got.author == author
  9. 26.

    Если надо бизнес-логику на фронт — TDD describe('ADD_ITEM mutation', ()

    => { it('Increases item quantity when adding the same item', () => { const state = store.state(); const product = productFactory({ id: 100500 }); store.mutations.ADD_ITEM(state, { product }); store.mutations.ADD_ITEM(state, { product }); expect(state.items).toHaveLength(1); expect(state.items[0].quantity).toEqual(2); }); });
  10. 29.
  11. 34.

    Две истории def test_class_marked_as_used(self): c = self._buy_a_lesson() entry = self._create_entry()

    self._schedule(c, entry) c.refresh_from_db() self.assertTrue(c.is_scheduled) with freeze_time('2032-12-01 16:30'): bill_timeline_entries() # run the periodic task by hand with self.assertRaises(ObjectDoesNotExist): entry.refresh_from_db() c.refresh_from_db() self.assertTrue(c.is_fully_used) self.assertEqual(AccEvent.objects.count(), 1) @pytest.fixture der _klass(factory, schedule): def create_a_class(schedule_to: datetime): klass = factory.klass() schedule(klass, date=schedule_to) return klass return _klass @pytest.mark.freeze_time('2032-12-01 16:30') def test_marking_class_as_used(_klass, freezer): klass = _klass(schedule_to='2032-11-01 15:30') # in the past bill_timeline_entries() # assert klass.is_fully_used is True
  12. 36.
  13. 37.

    Django templates <form action="/polls/{{ poll.id }}/vote/" method="POST"> {% for choice

    in poll.choice_set.all %} <input type = "radio" name="choice" id="choice_{{ forloop.counter }} value="{{ choice.id}}" /> <label for="choice_{{ forloop.counter }}">{{ choice.choice }}</label> {% endfor %} <input type="submit" /> </form>
  14. 42.

    class UserCreator: """Service object for creating a user""" def __init__(self,

    name, email, subscribe=True): self.do_subscribe = subscribe self.data = { 'email': email, 'username': email or str(uuid.uuid4()), 'subscribed': subscribe, **User.parse_name(name), } def __call__(self) -> User: self.resulting_user = self.get() or self.create() self.after_creation() return self.resulting_user Service Objects!