Журнал LinuxFormat - перейти на главную

LXF169: Web-раз­ра­бот­ка Django

Материал из Linuxformat
Версия от 08:22, 13 ноября 2018; Olkol (обсуждение | вклад)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Кар­кас для web-при­ло­же­ний. Про­грам­ми­ро­вание в Django.

Содержание

Вве­де­ние в Django

Джо­но Бэ­кон за­кру­ля­ет се­рию не­сколь­ки­ми со­ве­та­ми про­фес­сио­на­ла.

(thumbnail)
Наш эксперт Джо­но Бэ­кон управ­ля­ет со­об­ще­ст­вом Ubuntu; он ав­тор кни­ги «Ис­кус­ст­во со­об­ще­ст­ва» и ос­но­ва­тель еже­год­но­го сам­ми­та ру­ко­во­ди­те­лей со­об­ще­ст­ва.

В пре­ды­ду­щих трех час­тях этой се­рии о зна­ком­ст­ве с Django мы от­кры­ли несколь­ко основ­ных прин­ци­пов соз­дания мощ­но­го ди­на­ми­че­­ско­­го web-при­ло­жения. Мы по­го­во­ри­ли о на­строй­ке, ба­зах дан­ных, мо­де­лях, фор­мах, за­дании URL-ад­ре­сов, шаб­ло­нах, те­мах и др.

В этой чет­вер­той и по­следней ста­тье мы за­полним ряд остав­ших­ся в ма­те­риа­лах про­бе­лов и по­ко­па­ем­ся в прие­мах и со­ве­тах, спо­соб­ных вам при­го­дить­ся в по­все­днев­ном про­грам­ми­ро­вании с Django. Эта ста­тья пред­по­ла­га­ет на­ли­чие ба­зо­вых знаний во мно­гих из этих об­лас­тей, и в ней я по­ка­жу вам неко­то­рые ре­шения ря­да рас­про­странен­ных за­дач, ко­то­рых в этой се­рии мы еще не ка­са­лись.

(thumbnail)
> Рис. 1. На схе­ме удоб­но пред­став­ле­ны взаи­мо­свя­зан­ные от­но­ше­ния.

Но­вые трю­ки шаб­ло­нов

В пре­ды­ду­щей ста­тье мы уз­на­ли, как по­стро­ить ин­тер­фейс web-страницы с по­мо­щью шаб­ло­нов Django. Ос­но­вы мы рас­смот­ре­ли, но проч­ные знания язы­ка шаб­ло­нов Django по­мо­гут вам соз­дать луч­ший, бо­лее на­страи­вае­мый ин­тер­фейс.

При на­пи­сании шаб­ло­нов важ­но хо­ро­шо знать два основ­ных ти­па вы­ра­жений: цик­лы и усло­вия. Мы уже рас­смат­ри­ва­ли цик­лы с цик­лом for:

{% for i in content %}

Шаблон:I

{% endfor %}

При от­прав­ке дан­ных из пред­став­ления шаб­ло­ну обыч­но от­прав­ля­ет­ся на­бор эле­мен­тов, сгенери­ро­ван­ный за­про­сом, на­при­мер, так:

content = MyTable.objects.all()

return render_to_response(‘mytemplate.html’, {‘content’: content}, context_instance=RequestContext(request))

Тут по ним мож­но прой­тись в цик­ле for с при­ве­ден­ным вы­ше син­так­си­сом. Иногда нам ну­жен боль­ший кон­троль над от­прав­ляе­мы­ми шаб­ло­ну дан­ны­ми. Ска­жем, в раз­ных про­грам­мах на Python струк­ту­ры дан­ных пред­став­ля­ют­ся по-раз­но­му. Ес­ли за­прос по­до­бен при­ве­ден­но­му вы­ше, вы по­лу­чае­те спи­сок эле­мен­тов, по ко­то­ро­му лег­ко прой­тись в цик­ле. Но иногда мо­жет по­на­до­бить­ся восполь­зо­вать­ся сло­ва­рем – на­при­мер, так:

{ “one” : 1, “two” : 2, “three” : 3 }

То­гда дан­ные ге­не­ри­ру­ют­ся в пред­став­ле­нии и за­тем от­прав­ля­ют­ся стра­ни­це точ­но та­ким же об­ра­зом. Про­стой при­мер:

content = [ “one” : 1, “two” : 2, “three” : 3]

return render_to_response(‘mytemplate.html’, {‘content’: content}, context_instance=RequestContext(request))

Ите­ри­ро­вать та­кие дан­ные в шаб­ло­не нуж­но не­мно­го ина­че. Для это­го вос­поль­зу­ем­ся сле­дую­щим фор­ма­том:

{% for k, v in content.items %}

The key is Шаблон:K and the value is Шаблон:V

{% endfor %}

Здесь при­ме­ча­тель­ны несколь­ко мо­мен­тов. Во-пер­вых, мы ис­поль­зу­ем кон­ст­рук­цию .items по­сле ука­зания мас­си­ва content, по ко­то­ро­му идут ите­ра­ции – так мы по­лу­ча­ем ком­понен­ты струк­ту­ры дан­ных. За­тем мы по­лу­ча­ем два ком­понен­та, по­сколь­ку это сло­варь, и k ссы­ла­ет­ся на ключ, а v – на зна­чение. Мож­но сде­лать еще умнее – сфор­ми­ро­вать спи­сок сло­ва­рей следующим об­ра­зом:

content = [{ “one” : 1, “two” : 2 }, { “three” : 3 }, {“four” : 4 }]

Для ите­ра­ций по нему нуж­но сна­ча­ла соз­дать цикл по внешнему спи­ску, а внут­ри него вы­би­рать ка­ж­дый сло­варь и по­лу­чать зна­чения:

{% for item in content %}

{% for k, v in item.items %}

The key is Шаблон:K and the value is Шаблон:V

{% endfor %}

{% endfor %}

Еще один рас­про­странен­ный при­мер – сло­варь из сло­ва­рей, на­при­мер, при по­строении на­бо­ра дан­ных, ко­то­рые от­но­сят­ся к че­му-то. На­при­мер:

content = {

“bob” : { “job” : “Programmer”, “id” : 234},

“jane” : { “job” : “QA”, “id” : 245 },

}

Здесь у нас есть сло­варь для ка­ж­до­го ли­ца, а в сло­ва­ре – вся­кая ин­фор­ма­ция об этом ли­це. Об­ра­ти­те внимание, что в ка­ж­дом сло­ва­ре ис­поль­зу­ет­ся один и тот же ключ (здесь – job). Поз­же мы по­смот­рим, как ис­поль­зо­вать опе­ра­то­ры усло­вия в та­ких струк­ту­рах, а по­ка про­сто про­ите­ри­ру­ем его:

{% for name, info in content.items %}

Шаблон:Name

{% for k, v in info.items %}

Шаблон:K : Шаблон:V

{% endfor %}

{% endfor %}

У нас есть внешний цикл for, ко­то­рый про­хо­дит по име­нам и по­лу­ча­ет дан­ные в пе­ре­мен­ных name и info, и внут­ренний цикл, ко­то­рый про­хо­дит по сло­ва­рям из info.

Дру­гая рас­про­странен­ная си­туа­ция, в ко­то­рой вы од­на­ж­ды ока­же­тесь – соз­дание струк­ту­ры дан­ных, объ­е­ди­няю­щей вме­сте дан­ные мо­де­лей Django и дру­гие дан­ные. Пусть, на­при­мер, у нас есть таб­ли­ца People, и мы хо­тим до­ба­вить до­полнитель­ные дан­ные в струк­ту­ру дан­ных. В пред­став­лении они соз­да­ют­ся так:

people = People.objects.all()

content = {}

for person in people:

if person.clearance == 1:

content[person] = { “зда­ние” : “штаб”, “зна­ет­сек­ре­ты” : True }

else:

content[person] = { “зда­ние” : “офис”, “зна­ет­сек­ре­ты” : False }

return render_to_response(‘mytemplate.html’, {‘content’: content}, context_instance=RequestContext(request))

Здесь мы ис­поль­зу­ем объ­ект дан­ных как ключ внешнего сло­ва­ря, а зна­чение – наш сло­варь. Скажем, ес­ли в People есть запись “Bob” и у Бо­ба есть до­пуск, на­ша струк­ту­ра дан­ных бу­дет вы­гля­деть так:

{ <People: Bob> : { “зда­ние” : “штаб”, “зна­ет­сек­ре­ты” : True } }

Ите­ри­ро­вать­ся по ней мож­но так же, как в пре­ды­ду­щем при­ме­ре, но мож­но об­ра­щать­ся к по­лям объ­ек­та дан­ных. На­при­мер:

{% for name, info in content.items %}

Шаблон:Name.fullname has clearance level Шаблон:Name.clearance

{% for k, v in info.items %}

Шаблон:K : Шаблон:V

{% endfor %}

{% endfor %}

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

Ус­ло­вия и фильт­ры

Те­перь пе­ре­клю­чим пе­ре­да­чу и рас­смот­рим усло­вия в фильт­рах. Ус­ло­вия ис­поль­зу­ют­ся для про­вер­ки со­от­вет­ст­вия оп­ре­де­лен­ных пе­ре­мен­ных за­дан­ным зна­чениям, и в за­ви­си­мо­сти от ре­зуль­та­та про­вер­ки мож­но ото­бра­жать раз­лич­ную ин­фор­ма­цию.

Пусть, на­при­мер, у нас в пред­став­лении имеется та­кая струк­ту­ра дан­ных:

content = [ “admin”, “bob”, “jane” ]

Это про­стой спи­сок имен. Те­перь в на­шем шаб­лоне мож­но восполь­зо­вать­ся ко­ман­дой if, что­бы про­ве­рить, есть ли в спи­ске ад­минист­ра­тор, и вы­вес­ти для него дру­гое со­об­щение:

{% for name in content %}

{% if name == “admin” %}

Admin logged in

{% else %}

Normal user logged in

{% endif %}

{% endfor %}

Дру­гой спо­соб это сде­лать – вос­поль­зо­вать­ся ко­ман­дой ifequal [ес­ли рав­но]:

{% for name in content %}

{% ifequal name “admin” %}

Admin logged in

{% else %}

Normal user logged in

{% endifequal %}

{% endfor %}

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

Для это­го удоб­но восполь­зо­вать­ся фильт­ром length. На­при­мер, пред­ставь­те, что нам нуж­но вы­вес­ти спи­сок поль­зо­ва­те­лей из таб­ли­цы People. Вот как мож­но про­ве­рить, есть ли в таб­ли­це за­пи­си, и вы­вес­ти со­от­вет­ст­вую­щий ре­зуль­тат:

{% ifequal content|length 0 %}

No people.

{% else %}

{% for name in content %}

{% ifequal name “admin” %}

Admin logged in

{% else %}

Normal user logged in

{% endifequal %}

{% endfor %}

{% endifequal %}

Здесь мы поль­зу­ем­ся обыч­ным вы­ра­жением ifequal, но при­ме­ня­ем фильтр length к пе­ре­мен­ной content с по­мо­щью сим­во­ла |.

В Django есть несколь­ко по­лез­ных фильт­ров. Рас­смот­рим несколь­ко са­мых по­пу­ляр­ных. Пре­ж­де все­го, вам мо­жет по­на­до­бить­ся ото­бра­жать да­ты в раз­лич­ных фор­ма­тах – на­при­мер, оп­ре­де­лить локаль поль­зо­ва­те­ля и представить да­ту в со­от­вет­ст­вую­щем фор­ма­те (на­при­мер, 1-11-2013 вме­сто 11-1-2013). К объ­ек­ту datetime мож­но при­менить фильтр date, на­при­мер, так:

Шаблон:Value

Он от­фор­ма­ти­ру­ет да­ту следующим образом: Tue 08 Feb 2013. Бу­к­вы в этой стро­ке оп­ре­де­ля­ют фор­ма­ти­ро­вание да­ты, и есть мно­же­ст­во раз­лич­ных оп­ций для то­го, что­бы пред­ста­вить да­ту имен­но так, как вам нуж­но. Еще два по­лез­ных фильт­ра – dictsort и dictsortreversed, он сор­ти­ру­ет сло­варь, к ко­то­ро­му при­ме­ня­ет­ся. Дру­гие два – first и last, они воз­вра­ща­ют пер­вый и по­следний эле­мен­ты спи­ска. Не­ко­то­рые по­лез­ные фильт­ры при­ве­де­ны во врез­ке «Па­мят­ка по фильт­рам шаб­ло­нов».

До­бав­ление сво­их команд

В про­цес­се ра­бо­ты с Django вы очень близ­ко по­зна­ко­ми­тесь со скрип­том manage.py, вхо­дя­щим в ваш про­ект. Ча­ще все­го он ис­поль­зу­ет­ся для вы­полнения команд та­ким об­ра­зом:

python manage.py syncdb

python manage.py runserver

manage.py – швей­цар­ский ар­мей­ский нож в ар­се­на­ле Django. Он со­дер­жит ко­ман­ды для вы­полнения все­воз­мож­ных дей­ст­вий: соз­дания при­ло­жений, тес­тов, про­вер­ки мо­де­лей, ис­сле­до­вания ба­зы дан­ных и др. Но иногда мо­жет возник­нуть необ­хо­ди­мость в соб­ст­вен­ных ко­ман­дах, ко­то­рые мож­но вы­полнить с manage.py, на­при­мер, когда нуж­но восполь­зо­вать­ся в сво­ем про­ек­те на Django функ­ция­ми из дру­го­го про­ек­та, не на Django.

На­при­мер, не так дав­но я на­чал про­ект «Дости­жения в Ubuntu [Ubuntu Accomplishments]» – это сис­те­ма, ко­то­рая фик­си­ру­ет ва­ши дости­жения и на­гра­ж­да­ет вас при­за­ми за них. В рам­ках это­го про­ек­та я на­пи­сал сер­вер про­вер­ки, ко­то­рый про­ве­ря­ет при­зы на под­лин­ность для за­щи­ты от поль­зо­ва­те­лей, под­де­лы­ваю­щих свои при­зы.

По­тра­тив неко­то­рое вре­мя на на­пи­сание сер­ве­ра про­вер­ки, я по­нял, что мне ну­жен спо­соб ви­зуа­ли­за­ции оши­бок и про­блем, об­на­ру­жен­ных сер­ве­ром. В ка­че­­ст­ве та­ко­го спо­со­ба я вы­брал кли­ент на Django и при­нял­ся за ра­бо­ту.

В процессе работы я столк­нул­ся с про­бле­мой: когда сер­вер про­вер­ки об­на­ру­жит ошиб­ку – как до­ба­вить запись в ба­зу дан­ных Django, что­бы ее уви­дел кли­ент на Django? С од­ной сто­ро­ны, мож­но бы­ло бы об­но­вить ба­зу дан­ных вруч­ную, под­клю­чив­шись к ней на­пря­мую, но это неряш­ли­вый и шту­кар­ский под­ход. За­тем я уз­нал, что мож­но соз­дать поль­зо­ва­тель­скую ко­ман­ду для manage.py, ко­то­рая бы это де­ла­ла. Вот я и соз­дал ко­ман­ду addfailure, и сер­вер про­вер­ки про­сто вы­зы­вал ее при возник­но­вении ошиб­ки и пе­ре­да­вал ко­ман­де ин­фор­ма­цию об ошиб­ке. По­смот­рим, как соз­дать та­кую ко­ман­ду.

Эти раз­лич­ные ко­ман­ды manage.py свя­зы­ва­ют­ся с при­ло­жением. Мож­но соз­дать на­бор команд для ка­ж­до­го при­ло­жения в про­ек­те. На­при­мер, пред­по­ло­жим, что у нас есть про­ект Django для хранения спи­ска со­трудников ком­пании. В этом про­ек­те есть мо­дель ‘Staff [Штат]’, ко­то­рая хранит спи­сок со­трудников. Пред­по­ло­жим так­же, что при­ло­жение на­зы­ва­ет­ся ‘company [ком­пания]’.

Управ­ление

Поль­зо­ва­тель­скую функ­цио­наль­ность, от­но­ся­щую­ся к скрип­ту manage.py, на­зо­вем Management [Управ­лением]. Для на­ча­ла нуж­но соз­дать ка­та­лог management внут­ри на­ше­го при­ло­жения, а за­тем, внут­ри это­го ка­та­ло­га, ка­та­лог commands, где бу­дут хранить­ся на­ши ко­ман­ды (в дан­ном слу­чае, у нас по­лу­чи­лось company/management/commands).

Те­перь соз­да­дим поль­зо­ва­тель­скую ко­ман­ду и на­зо­вем ее addstaffmember [До­ба­вить со­трудника]. Для это­го соз­дай­те файл addstaffmember.py в ка­та­ло­ге commands. В этом ка­та­логе так­же нуж­но соз­дать пустой файл __init__.py. Те­перь от­кро­ем addstaffmember.py и до­ба­вим в него немно­го ко­да.

Сна­ча­ла нуж­но за­гру­зить неко­то­рые мо­ду­ли, ко­то­ры­ми мы восполь­зу­ем­ся для реа­ли­за­ции ко­ман­ды:

from django.core.management.base import BaseCommand, CommandError

Те­перь соз­да­дим но­вый класс Command ти­па BaseCommand и до­ба­вим в него функ­цию handle, в ко­то­рой бу­дет хранит­ся ло­ги­ка ко­ман­ды:

class Command(BaseCommand):

def handle(self, *args, **options):

print “hello world”

Со­храните файл. К сча­стью, Django до­воль­но умен и ав­то­ма­ти­че­­ски ре­ги­ст­ри­ру­ет все ко­ман­ды из ка­та­ло­га commands, ко­то­рые не на­чи­на­ют­ся с сим­во­ла под­чер­ки­вания. По­это­му, за­пустив ко­ман­ду python manage.py, вы долж­ны уви­деть и свою ко­ман­ду в спи­ске. Для пол­но­ты кар­ти­ны до­ба­вим ко­рот­кую стро­ку с опи­санием то­го, что де­ла­ет ко­ман­да. Эта стро­ка поя­вит­ся, когда кто-то за­пустит python manage.py help addstaffmember. Для это­го до­бавь­те стро­ку help по­сле оп­ре­де­ления клас­са:

class Command(BaseCommand):

help = ‘до­ба­вить со­труд­ни­ка в ба­зу дан­ных’

В те­ку­щем ви­де на­ша ко­ман­да не осо­бо по­лез­на. Нам нуж­но нау­чить­ся принимать на­бо­ры ар­гу­мен­тов, ко­то­рые мы смо­жем об­ра­бо­тать и до­ба­вить в ба­зу дан­ных. Сна­ча­ла оп­ре­де­лим ар­гу­мен­ты, ко­то­рые мы принима­ем, для че­го за­да­дим пе­ре­мен­ную args точ­но так же, как ранее за­да­ва­ли пе­ре­мен­ную help. Внут­ри пе­ре­мен­ной args мы ука­жем принимае­мые ар­гу­мен­ты. На­при­мер:

class Command(BaseCommand):

args ‘firstname lastname job’

help = ‘до­ба­вить со­труд­ни­ка в ба­зу дан­ных’

Ес­ли те­перь за­пустить python manage.py help addstaffmember, вы уви­ди­те стро­ку help и спи­сок ожи­дае­мых ар­гу­мен­тов ко­ман­ды. Хо­тя мы оп­ре­де­ли­ли эти ар­гу­мен­ты, их име­на не точ­но со­от­вет­ст­ву­ют пе­ре­мен­ным скрип­та. Вме­сто это­го нуж­но про­честь ар­гу­мент по его по­ло­жению и за­пи­сать его зна­чение в пе­ре­мен­ную. На­при­мер:

item_firstname = args[0]

item_lastname = args[1]

item_job = args[2]

Мы счи­та­ли свои дан­ные, и мож­но до­ба­вить их в ба­зу. Для на­ча­ла за­гру­зим на­шу мо­дель:

from company.models import Staff

Те­перь мож­но соз­дать за­пись Staff, в ко­то­рую мы пе­ре­да­ем дан­ные пе­ре­мен­ных и за­тем со­хра­ня­ем ее в ба­зу дан­ных:

entry = Staff.objects.create(firstname=item_firstname, lastname=item_lastname, job=item_job)

entry.save()

На­ша ко­ман­да го­то­ва! Мож­но про­ве­рить ее так:

python manage.py testcommand “Alan” “Cox” “Kernel Programmer”

Когда мы за­пустим эту команду, на­ша таб­ли­ца Staff об­но­вит­ся, и вы долж­ны уви­деть ее в сво­ем про­ек­те! Вот пол­ный скрипт ко­ман­ды:

from django.core.management.base import BaseCommand, CommandError

from company.models import Staff

class Command(BaseCommand):

args = ‘firstname lastname job’

help = ‘Adds a staff member to the database.’

def handle(self, *args, **options):

item_firstname = args[0]

item_lastname = args[1]

item_job = args[2]

entry = Staff.objects.create(firstname=item_firstname, lastname=item_lastname, ob=item_job)

entry.save()

Понимание сво­их мо­де­лей

Как и у боль­шин­ст­ва но­вич­ков в Django, в ва­ших пер­вых про­ек­тах бу­дет со­всем немно­го мо­де­лей. По ме­ре освоения сис­те­мы, с ростом про­ек­тов от неболь­ших до пол­но­цен­ных при­ло­жений, ко­то­ры­ми долж­ны бу­дут поль­зо­вать­ся и дру­гие, ва­ши мо­де­ли бу­дут рас­ти и рас­ши­рять­ся. Вско­ре у вас бу­дет ог­ром­ный спи­сок взаи­мо­свя­зан­ных мо­де­лей, и с из­менением ди­зай­на и функ­цио­наль­но­сти бу­дут ме­нять­ся и ва­ши мо­де­ли. В ре­зуль­та­те вы бу­де­те улуч­шать свои мо­де­ли шаг за ша­гом в на­де­ж­де соз­дать окон­ча­тель­ную вер­сию ди­зай­на, что­бы боль­ше не из­ме­нять мо­де­ли, когда про­ект начнет ис­поль­зо­вать­ся.

Пе­ред окон­ча­тель­ным ре­ли­зом вы, ве­ро­ят­но, за­хо­ти­те пол­но­стью про­смот­реть свои мо­де­ли, что­бы убе­дить­ся, что в них нет ника­ких бес­смыс­лен­ных свя­зей. Под­роб­но рас­смот­реть та­кое мно­же­ст­во взаи­мо­свя­зан­ных мо­де­лей слож­но. По­это­му по­лез­но иметь схе­му всех сво­их мо­де­лей и свя­зей ме­ж­ду ними. К сча­стью, си­деть и ри­со­вать ее вруч­ную не при­дет­ся – ее мож­но сгенери­ро­вать ав­то­ма­ти­че­­ски.

Для это­го нуж­но уста­но­вить рас­ши­рения Django (Django Extensions). Это на­бор по­лез­ных до­полнений к функ­цио­наль­но­сти manage.py. Для ва­ше­го ди­ст­ри­бу­ти­ва дол­жен быть со­от­вет­ст­вую­щий па­кет (на­при­мер, в Ubuntu я уста­но­вил python-django-extensions). Ис­ход­ный код мож­но за­гру­зить на­пря­мую с https://github.com/django-extensions/django-extensions.

Что­бы восполь­зо­вать­ся рас­ши­рения­ми, нуж­но убе­дить­ся, что они до­бав­ле­ны как при­ло­жение в settings.py ва­ше­го про­ек­та в раз­дел INSTALLED_APPS. До­бавь­те в INSTALLED_APPS сле­дую­щее:

django_extensions

Для по­строения схе­мы нуж­но за­пустить ко­ман­ду, ко­то­рая сгенери­ру­ет схе­му GraphViz; это спе­ци­аль­ный язык раз­мет­ки, ис­поль­зуе­мый для генера­ции схем. Обыч­но за­тем с по­мо­щью дру­гой ути­ли­ты схе­ма кон­вер­ти­ру­ет­ся в удоб­ный для про­смот­ра вид. И все это мож­но сде­лать од­ной ко­ман­дой!

python manage.py graph_models company -a -g -o my_project.png

Здесь мы вы­пол­ня­ем ко­ман­ду graph_models для при­ло­жения company и генери­ру­ем файл my_project.png с на­шей схе­мой. При­мер та­кой схе­мы по­ка­зан на рис. 1.

Django – фан­та­сти­че­­ский каркас для соз­дания мощ­ных web-при­ло­жений с воз­мож­но­стя­ми, рас­ши­ряе­мо­стью и удо­воль­ст­ви­ем от ра­бо­ты, сравнимы­ми со всем этим при на­пи­сании при­ло­жений на Python. В на­шей се­рии мы ис­сле­до­ва­ли мно­же­ст­во тем, но мно­гие оста­лись за ее рам­ка­ми. Ре­ко­мен­дую по­гру­зить­ся в превосходную до­ку­мен­та­цию на https://docs.djangoproject.com/en – и обя­за­тель­но за­да­вать во­про­сы на сай­тах http://stackoverflow.com, по­ме­чая их тэ­гом Django. Еще один пре­крас­ный ис­точник по­мо­щи – ка­нал #django в IRC-се­ти Freenode.

Ес­ли вы сле­до­ва­ли за на­ми в те­чение всей се­рии о Django, спа­си­бо вам за это. Уда­чи с бу­ду­щи­ми про­ек­та­ми, и обя­за­тель­но со­об­щи­те мне о сво­их успе­хах. Все­го доб­ро­го! |

Персональные инструменты
купить
подписаться
Яндекс.Метрика