...

воскресенье, 25 августа 2013 г.

Пишем backend для мобильного приложения за несколько минут

Здравствуйте! Моя основная область деятельности — разработка мобильных приложений (iOS, Android). И большая часть приложений, использует взаимодействие с другими пользователями, хранение данных и другие задачи требующие наличие единого сервера. Поэтому для большей части приложений приходится писать свой велосипедbackend. А так как я, в основном являюсь мобильным разработчиком, то написание этого сервиса всегда становится небольшой проблемой — приходится задействовать веб-разработчика или искать подходящий BaaS сервис, даже если надо написать всего пару запросов.

Поэтому было принято решение, попробовать найти инструмент, позволяющий в короткие сроки написать небольшой веб-сервис, который можно было бы использовать в мобильном приложении.



За исходные данные были приняты: знание что такое HTTP, REST, JSON и начальный уровень разработки на Python (Django).

И вот на днях, на глаза попался небольшой проект, на котором можно было провести полевые испытания. Суть проекта — приложение для одного мероприятия. Нужно отображать спикеров и их доклады.

После непродолжительных поисков, за основу были взяты следующие инструменты: Python (как основной язык разработки), Django (как базовая платформа) и фреймворк Tastypie (представленный как фреймворк для создания API веб-сервисов). Итак, приступим.

Создаем шаблон приложения Django:

python django-admin.py startproject EventApp




В настройках файла settings.py прописываем необходимые настройки для базы данных, локализацию, время. Устанавливаем пакет tastypie:

pip install django-tastypie




Обратите внимание, что требуется Python2.6+ и Django 1.5+. Из-за незнания этого факта пришлось потратить немного больше времени, т.к. фреймворк отказывался работать. Кроме того, нужно установить аналогичным образом пакет python-mimeparse.

Далее, в файле settings.py, прописываем:

INSTALLED_APPS += ['tastypie']




или добавляем уже в существующий список приложение ‘tastypie’.

Теперь пропишем модели нашей предметной области:

# -*- coding: utf-8 -*-
from django.db import models


class Speaker(models.Model):
name = models.CharField(max_length=32)
company = models.CharField(max_length=32)
photo = models.ImageField(upload_to='photos', blank=True, null=True)

def __unicode__(self):
return self.name + ' (' + self.company + ')'


class Event(models.Model):
title = models.CharField(max_length=64)
speaker = models.ForeignKey(Speaker, blank=False, null=False)
start_time = models.TimeField()
end_time = models.TimeField()

def __unicode__(self):
return self.title + ' (' + self.speaker.name + ')'




Мы написали модель докладчика (Speaker) и модель выступления (Event). У каждого выступления обязательно есть докладчик. Теперь, сделаем так, чтобы мы могли полноценно работать с нашими моделями как с ресурсами через REST протокол.

Создаем в нашем приложении пакет api и файлом resources.py (или можно его создать в основном пакете).

from tastypie.resources import ModelResource
from EventApp.models import Speaker, Event


class SpeakerResource(ModelResource):
class Meta:
queryset = Speaker.objects.all()
resource_name = 'speaker'


class EventResource(ModelResource):
speaker = fields.ForeignKey(SpeakerResources, 'speaker', blank=True, null=True)
class Meta:
queryset = Event.objects.all()
resource_name = 'event'




В этом файле мы создали классы, так называемых ресурсов, основных объектов в нашем REST сервисе. Это как раз те ресурсы, к которым мы будем обращаться. Каждый класс содержит ссылку на ту модель, которую он представляет. Поле queryset возвращает нам набор объектов получаемых из базы при обращении к даному ресурсу. Поле resource_name необязательно, и позволяет нам указать дополнительно наименование ресурса, по которому он будет доступен нам.

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

Теперь осталось только прописать в файле urls.py обращения к нашему сервису. Это делает очень просто.

from django.conf.urls.defaults import *
from tastypie.api import Api
from api.resources import EventResource, SpeakerResource

v1_api = Api(api_name='v1')
v1_api.register(SpeakerResource())
v1_api.register(EventResource())

urlpatterns = patterns('',
(r'^api/', include(v1_api.urls)),
)





Теперь запускаем наш проект

python manage.py runserver




Теперь, если сервер успешно запустился, открыв в браузере страницу по адресу http://localhost:8000/api/entry/?format=json, увидим там что фреймворк видит все наши ресурсы и отобразил нам схему нашего сервиса:

{
"events":
{
"list_endpoint": "/api/v1/events/"
, "schema": "/api/v1/events/schema/"
}
,"speakers":
{
"list_endpoint": "/api/v1/speakers/"
,"schema": "/api/v1/speakers/schema/"
}
}




Параметр format принудительно указывает в каком формате мы хотим получить данные, но вместо него можно в запросе указать заголовок Content-type: application/json. Кроме JSON поддерживаются xml, yaml, bplist.

По адресу schema можно посмотреть описание структуры модели (поля, типы и описание), а по адресу list_endpoint можно уже получить наши ресурсы, которые мы предварительно записали в базу.

Теперь, открыв адрес http://localhost:8000/api/v1/events/?format=json мы увидим там что-то вроде этого:

{
"meta":
{
"limit": 20
,"next": null
,"offset": 0
,"previous": null
,"total_count": 4
}
,"objects": [
{
"id": 3
,"speaker": "/api/v1/speakers/2/"
,"start_time": "08:39:25"
,"end_time": "18:39:29"
,"title": "Ранее что нибудь"
,"description": "описание"
}
]
}




Как видим — ничего сложного. В разделе meta выводится основная информация о ресурсе: количество записей, размер выдачи и тд. Одновременно мы можем обратиться к конкретному событию, обратившись к ресурсу по его id — http://localhost:8000/api/v1/events/1/

Можем создать запись выполнив POST запрос и передав в него объект в JSON формате, обновить запись PUT запросом и удалить с помощью DELETE.

Так же, в tastypie у класса ModelResource есть большой набор переопределяемых полей и методов, с помощью которых мы можем полностью изменить структуру выдаваемых данных. Например, мы хотим вместо ссылки на спикера, сразу получать его имя, чтобы не делать лишний запрос. В классе EventResource переопределяем метод dehydrate:

def dehydrate(self, bundle):
try:
speaker = Speaker.objects.filter(id=bundle.obj.speaker.id)
bundle.data['speaker_name'] = speaker[0].name
except Speaker.DoesNotExist:
pass
return bundle




В нем, мы находим спикера в базе и подставляем его в объект bundle, который представляет из себя словарь который отдается ресурсом. Теперь, ответ на запрос будет выглядеть так (напишу только основную часть):

{
"id": 3
,"speaker": "/api/v1/speakers/2/"
,"speaker_name": "Василий"
,"start_time": "08:39:25"
,"end_time": "18:39:29"
,"title": "Ранее что нибудь"
,"description": "описание"
}




Что нам и требовалось! Кроме того, запрос к ресурсу можно сделать с параметрами для фильтрации.

Например, нам надо выбрать все события для одного докладчика. Логичен был бы следующий запрос:

http://localhost:8000/api/v1/events/?speaker=1 который вернет нам события, спикерами которых является спикер с id = 1. Необходимо только прописать в meta класс ресурса еще одно поле:

filtering = {
'speaker': ALL_WITH_RELATIONS
}


Заключение



Отлично! Теперь мы уже можем обращаться к серверу, получать от него данные. А ведь именно это нам и требовалось.

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

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends: 'You Say What You Like, Because They Like What You Say' - http://www.medialens.org/index.php/alerts/alert-archive/alerts-2013/731-you-say-what-you-like-because-they-like-what-you-say.html


Комментариев нет:

Отправить комментарий