ФорумПрограммированиеPython → Db access adapter - как бы сделать лучше?

Db access adapter - как бы сделать лучше?

  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 18 апреля 2014 г. 12:33

    Эдво? Ты как самый опытный в python.

    Ситуация.

    Есть некоторое хранилище данных, к нему необходимо адаптер. Есть два момента для использования.

    • Используется как правило (99%) одни авторизационные данные для доступа к базе.

    • Но на всякий случай надо бы оставить возможность использования больше одних авторизационных данных для доступа.

    • хочется шорткаты на функции сделать, тобишь default авторизация должна быть. One time configuration, many executes.

    Сижу голову бля ломаю как лучше бы сделать и python way более менее.

    В итоге пришла вообще идея из серии

    Есть набор сервисов (в виде контейнер-объекта), у которого есть методы например get_by_id, get_by_slug и тп. Этот объект зависит от базового adapter который в себе несет грубо говоря функционал для fetch, в том числе информацию о авторизации и тп.

    И для удобства думаю вынести shortcuts функции. Типа прокси функции в виде

    def get_by_id(id):
    return get_default_adapter().service.get_by_id(id)

    Как тебе? Есть идеи в чем я сделал жесткую ошибку?

    шоркаты хочу для красоты кода, чтобы их можно было импортировать, не тягая тонны кода каждый раз на call'ы.

    Сапожник без сапог
  • adw0rd

    Сообщения: 22959 Репутация: N Группа: в ухо

    Spritz 19 апреля 2014 г. 11:51, спустя 23 часа 18 минут 13 секунд

    А что вообще тебя побудило делать эту задачу? Мне контекста побольше

    https://smappi.org/ - платформа по созданию API на все случаи жизни
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 19 апреля 2014 г. 12:45, спустя 53 минуты 49 секунд

    @adw0rd, необходимсть зп 😺👍

    Сапожник без сапог
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 5 мая 2014 г. 23:57, спустя 16 дней 11 часов 12 минут

    0.1 beta хуйль уже работает как я задумывал. получилось на мой взгляд идеально.

    from django.http import Http404
    from xxxlibrary.shortcuts.invoices import get_invoice_by_key
    
    class InvoiceObject(object):
        def get_object(self, queryset=None):
            """
            :type self: View
            """
            invoice_id = self.request.GET.get('invoice')
            if not invoice_id:
                raise Http404
    
            invoice = get_invoice_by_key(invoice_id)
    
            return invoice
    

    пример миксина, который использует adapter.

    Дальше магия конечно же :-)

    from django.views.generic import DetailView
    from render.mixins import RenderViewMixin
    from project.payment.mixins import InvoiceObject
    
    class Index(InvoiceObject, RenderViewMixin, DetailView):
        pass
    

    Вот так устанавливается в жангу

    MIDDLEWARE_CLASSES += ('xxxlibrary.middleware.ApiClientMiddleware', )
    

    Минимальная конфигурация

    ADAPTER_API_ID = 'int id'
    ADAPTER_API_SECRET = 'my secret string'
    

    пример шорткатов

    def get_invoice_by_key(id):
        return get_apiclient().services.invoices.get_invoice_by_key(id)
    

    дохуя делов переделано, все переписал, щас у меня api client вообще компилится по серверному прототипу для всех методов. своеобразный SOAP wsdl короче говоря)

    Ну и get_apiclient реализовано как i18n/tz в жанге. через активацию из мидлваря

    _active = local()
    
    def get_apiclient():
        """
        :rtype: ApiClient
        """
        if not hasattr(_active, "value"):
            raise ValueError('Not activated any apiclient. Please ``activate`` apiclient first')
    
        client = _active.value
        assert isinstance(_active.value, ApiClient)
    
        return client
    

    Спустя 23 сек.

    евгип хуйль! 👍

    Сапожник без сапог
  • adw0rd

    Сообщения: 22959 Репутация: N Группа: в ухо

    Spritz 7 мая 2014 г. 21:05, спустя 1 день 21 час 7 минут

    Крут, но особо не понял зачем, так как не знаю для каких целей

    https://smappi.org/ - платформа по созданию API на все случаи жизни
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 7 мая 2014 г. 21:18, спустя 13 минут 27 секунд

    Крут, но особо не понял зачем, так как не знаю для каких целей

    @adw0rd, у нас магазин торгующий гавном оптом. построен он в виде большой CRM на бекенде для работы с заказами, планированием, доставкой, платежами и тп, всякими бухгалтериями, дохуя делов короче.

    добавление заказов в него происходит посредствам апи функций. апи функций если я не ошибаюсь на память, порядка 83 штук.

    наши же сайты, куда приходят лохи и покупают гавно, устроены как api client к этой CRM. оттуда берется все наполнение товарами, категориями, гео данными и тп. представь magento которая работала бы полностью через апи :-D

    вот это примерно то что у нас есть.

    держать в голове все эти функции нет желания по понятной причине + следить за типами, параметрами, обязательностью их и тп. это чудовищный гемор, поэтому в апи две составляющих - апи сервер и апи клиент. раньше был под пхп апиклиент в котором все руками прописано, щас я закончил первую версию клиента который полностью code generated как кодогенерация прототипов из wsdl в тяжелых языках типа явы и .net.

    полное описание функций, все параметры их, возвращаемые типы данных и мапинг в локальные классы (которые тоже генерируются) это все для быстрой разработки на основе апи клиента)

    для custom функций в генераторе поддерживаются миксины.

    ну и docstrings для помощи в навигации всего этого пиздеца.

    вот пример генерируемого класса утилитарного (для пхп нужно было в общем то, но все же)

    from xxxlibary.mapping.mixins import Collection as CollectionMixin
    from xxxlibary.client.types import Object
    
    
    class Collection(CollectionMixin):
    
        """
        :type items: list of Object
        """
    
        def __init__(self, *args, **kwargs):
            self.count = None
            self.items = None
            self.offset = None
            self.total = None
    
            super(Collection, self).__init__(*args, **kwargs)
    

    сложные ольшие модели поля у которых желательно "подсветить", иначе разработка скатывается в code 95% navigation.

    class Product(Object):
    
        """
        :type categories: list|Collection
        :type children: list of Child|Collection
        :type complex: bool
        :type id: int
        :type price_text: str
        :type properties: str
        :type slug: str
        :type weight: int
        """
    
        def __init__(self, *args, **kwargs):
            self.available = None
            self.categories = None
            self.children = None
            self.comment = None
            self.complex = None
            self.composition = None
            self.compositions_info = None
            self.description = None
            self.id = None
            self.order = None
            self.price = None
            self.price_text = None
            self.prices = None
            self.priceusd = None
            self.properties = None
            self.realprice = None
            self.realprices = None
            self.realpriceusd = None
            self.search_tags = None
            self.slug = None
            self.title = None
            self.type = None
            self.url = None
            self.weight = None
    
            super(Product, self).__init__(*args, **kwargs)
    

    тем самым я добился охуенности ) я на сервере меняю параметры у функций и тп, что хочу, новые типы данных прописываю, у моделей поля хинтую по типам, и через "экспорт апи" я все это дело экспортирую, а питон клиент генерирует сам свою структуру типов данных и доступных функций)

    дохуя зайцев одним выстрелом. не надо в 4 местах прописывать одни и теже названия классов, функций, полей и тп.

    на стороне апи сервера парсинг, на клиенте code build.

    вот пример имплементации сервиса на клиентском апи

    class Shop(Service):
    
        def get_categories_list(self, parent_id=None):
            """
            :rtype : Category
            """
            return self._callapi("shop/categories", get={"parent_id": parent_id})
    
        def get_category_by_id(self, id):
            """
            :rtype : Category
            """
            return self._callapi("shop/category", get={"id": id})
    
        def get_currencies_list(self):
            """
            :rtype : list of Currency|Collection
            """
            return self._callapi("shop/currencies")
    
    Сапожник без сапог
  • adw0rd

    Сообщения: 22959 Репутация: N Группа: в ухо

    Spritz 8 мая 2014 г. 11:33, спустя 14 часов 15 минут 8 секунд

    Теперь понял , красавчик! А чего поля в ините прописал, а не сразу в классе?

    https://smappi.org/ - платформа по созданию API на все случаи жизни
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 8 мая 2014 г. 13:55, спустя 2 часа 21 минуту 45 секунд

    @adw0rd, ну с None так еще бы сканало, а так в принципе можно mutable поле получить случайно ))))) не имею практики прописывать в классах, чтобы неверняка. только в моделях жанги, ибо там автоматика все сожрет как надо. и еще второй вариант почему так - возможно pycharm не жрал их хинты под docstring'и, точно не помню, вполне могло быть такое, я тож долго подолбился чтобы все нормально хавалось с этим)

    геморная штука короче слегка, вот оптимизирую так работу)

    Сапожник без сапог
  • adw0rd

    Сообщения: 22959 Репутация: N Группа: в ухо

    Spritz 8 мая 2014 г. 14:12, спустя 17 минут 5 секунд

    Понял

    https://smappi.org/ - платформа по созданию API на все случаи жизни

Пожалуйста, авторизуйтесь, чтобы написать комментарий!