Advertisement
johnmahugu

python - djangol ferris cheatsheet and minidjngo

Jul 23rd, 2015
317
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 35.52 KB | None | 0 0
  1. = Template Tags Cheat Sheet =
  2.  
  3. == Inheritance and Inclusion ==
  4.  
  5.  * {% extends "base.html "%}
  6.  * {% block content %} ... {% endblock %} or {% block content %} ... {% endblock content %}
  7.  * {% include "foo/bar.html" %}
  8.  * {% ssi /home/html/ljworld.com/includes/right_generic.html %}
  9.  
  10. == Filters and Tags ==
  11.  
  12.  * {% load <tag_or_filter_lib> %}
  13.  * {% filter <filter>[|<filter>...] %}
  14.  
  15. == Control ==
  16.  
  17.  * {% for o in some_list %} ... {% endfor %}
  18.  * {% ifchanged %} (Content to check status of) {% endifchanged %}
  19.  * {% if <var> %} ... {% endif %}
  20.  * {% if[not]equal user.id comment.user_id %} ... [{% else %}] ... {% endif[not]equal %}
  21.  * {% cycle row1,row2 %}
  22.  * {% cycle row1,row2 as rowcolors %}
  23.  ** {% cycle rowcolors %}
  24.  * {% firstof var1 var2 var3 %}
  25.  * {% regroup people by gender as grouped %} ... {% for group in grouped %} {{ group.grouper }} ...
  26.  
  27. == Others ==
  28.  
  29.  * {% templatetag  (openblock|closeblock|openvariable|closevariable|openbrace|closebrace) %}
  30.  * {% widthratio this_value max_value 100 %}
  31.  * It is {% now "jS F Y H:i" %}
  32.  * {% spaceless %} ... {% endspaceless %}
  33. django_db_cheat.txtPage 1 of 2 Aug/2008
  34. 1#Model of question:2
  35. class
  36.  Blog(models.Model): 3 name=models.CharField(max_length=100) 4 tagline=models.TextField() 5 bestEntry=ForeignKey("mutually_referential.Entry")  6# two way relations usually illegal unless specified as referential7# myId = models.AutoField(primary_key=True)8# by default the primary key is called 'id' - but overridable9# 'blog.pk' to will refer to the primary key regardless of what its called1011
  37. class
  38.  Author(models.Model): 12 name=models.CharField(max_length=50) 13 email=models.EmailField() 1415
  39. class
  40.  Entry(models.Model): 16 blog=models.ForeignKey(Blog)  17# automagically in any Blog instance b, there is now a set called b.entry_set18# blog = models.ForeignKey(Blog, related_name='custom_name')19# (this overrides default name of blog.entry_set with blog.custom_name)20 headline=models.CharField(max_length=255) 21 body_text=models.TextField() 22 pub_date=models.DateTimeField() 23 authors=models.ManyToManyField(Author) 24
  41. class
  42.  Meta:25 ordering= ('-pub_date', 'headline') 26
  43. def
  44.  articles_from_same_day(self): 27
  45. return
  46. Entry.objects.filter(pub_date=self.pub_date).exclude(id=self.id) 28# a.articles_from_same_day() returns a resultset2930
  47. class
  48.  EntryDetail(models.Model): 31 entry=models.OneToOneField(Entry) 32 details=models.TextField() 3334#Inserting35 b=Blog(name='Beatles Blog',tagline='All the latest Beatles news.') 36 b.save() 37 bb=Blog(id=3,name='Not Cheddar',tagline='Anything but cheese.') 38 bb.save() # Overrides the previous blog with ID=3! 3940#Manager41 Entry.objects.get(id=2) # gets id=2 42 e=Entry.objects.select_related().get(id=2) 43
  49. print
  50. e.blog# Doesn't hit the database twice; uses cached version. 4445#Filter and Exclusion - it is a lazy operation, not done until iterated/read46 Entry.objects.filter(pub_date__year=2006) 47 Entry.objects.filter( 48 headline__startswith='What').exclude( 49 pub_date__gte=datetime.now()).filter( 50 pub_date__gte=datetime(2005, 1, 1))  51 Entry.objects.filter(blog=b) # Query using object instance 52 Entry.objects.filter(blog=b.id) # Query using id from instance 53 Entry.objects.filter(blog=5) # Query using id directly 5455#Sorting56 Entry.objects.order_by('pub_date', '-headline') 5758# Deleting59 e.delete() #If there are dependencies, they will be deleted too 60 Entry.objects.filter(pub_date__year=2005).delete() 61# warning - when deleting a resultset, you might delete many entries6263# Updating64 e.headline= 'Everything is the same' 65 e.save()
  51. - 1 -
  52. django_db_cheat.txtPage 2 of 2 Aug/2008
  53. 66 Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')  67 Entry.objects.all().update(blog=b) 68# need to save if you use bulk69
  54. for
  55. item
  56. in
  57. Entry.objects.all(): 70 item.save() 7172# Many-to-One - via ForeignKey73 b=Blog.objects.get(id=1) 74 b.entry_set.all() # Returns all Entry objects related to Blog. 75 b.entry_set.filter(headline__contains='Lennon') 76 b.entry_set.count() 77 e=Entry.objects.get(id=234) 78 b.entry_set.add(e) # Associates Entry e with Blog b. 79 e=b.entry_set.create(headline='Hello',body_text='Hi',pub_date=datetime.date(2005, 1, 1)) 80 b.entry_set.remove(e) # Disassociates Entry e from Blog b. 81 b.entry_set.clear() 82 b.entry_set= [e1,e2] # You can't set to one element need [e1,] 8384# One-to-One - via OneToOneField85 ed=EntryDetail.objects.get(id=2) 86 ed.entry# Returns the related Entry object. 87 e=Entry.objects.get(id=2) 88 e.entrydetail89 e.entrydetail=ed 9091# Many-to-Many - via ManyToManyField92 e=Entry.objects.get(id=3) 93 e.authors.all() # R
  58.  
  59. eturns all Author objects for this Entry.94 e.authors.filter(name__contains='John') 95 a=Author.objects.get(id=5) 96 a.entry_set.all() # Returns all Entry objects for this Author. 97 a.entry_set.filter(body_text__contains='John') 98 a.entry_set.create(....) #just like normal create 99100# Misc functions101 Author.objects.get_or_create(name='David',defaults={'email': 'generic@email.com'}) 102103# Returning a url to go to object:104# suppose your urlconf had105# (r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view)106
  60. from
  61. django.db.models
  62. import
  63. permalink107
  64. def
  65.  get_absolute_url(self): 108
  66. return
  67.  ('archive_view', (), { 109'year':self.created.year, 110'month':self.created.month, 111'day':self.created.day}) 112 get_absolute_url=permalink(get_absolute_url) 113114# Doing custom sql:115
  68. def
  69.  my_custom_sql(self): 116
  70. from
  71. django.db
  72. import
  73. connection117 cursor=connection.cursor() 118 cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz]) 119 row=cursor.fetchone() 120
  74. return
  75. row121122# Field Type Reference123 AutoField,BooleanField,CharField,CommaSeparatedIntegerField,DateField,DateTimeField,  124 DecimalField,EmailField,FileField,FilePathField,FloatField,ImageField,IntegerField,  125 IPAddressField,NullBooleanField,PhoneNumberField,PositiveIntegerField,  126 PositiveSmallIntegerField,SlugField,SmallIntegerField,TextField,TimeField,URLField,  127 USStateField,XMLField128129# Model Methods130 __unicode__,get_absolute_url
  76. - 2 -
  77. Quick and simple urlpatterns code examples for django cheatsheet
  78. See more
  79.  
  80. django_url_cheat.txtPage 1 of 2 Aug/2008
  81. 1
  82. from
  83. django.conf.urls.defaults
  84. import
  85.  *2 urlpatterns=patterns('', 3# (regular exp, function, optional dictionary, optional name)4# Doesn’t differentiate request method, all go to the same function5(r'^articles/2003/$', 'news.views.special_case_2003'),  6# "/articles/2003" -> no match need "2003/"7(r'^articles/(\d{4})/$', 'news.views.year_archive'), 8# ordering matters9# "/articles/2003/" -> news.views.special_case_2003, not news.views.year_archive(2003)10(r'^articles/special/(?P<year>\d{4})/$', 'news.views.year_archive'), 11# "/articles/special/2003" -> news.views.year_archive(request, year='2003')12(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'), 13(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'), 14# "/articles/2003/03/3/" -> news.views.article_detail(request, '2003', '03', '3')15)16 urlpatterns+=patterns('sports.views', # append like a list 17(r'^sports/2003/$', 'some_function'), 18# "/sports/2003/" -> sports.views.some_function(request)19)2021# Generic actions are useful if you are doing something generic such as:22# by default {'extra_context':{}}, add more context into extras if necessary23 urlpatterns+=patterns('django.views.generic.simple',  24(r'^page_new/(?P<id>\d+)/$', 'direct_to_template', {'template': 'page_detail.html'}),) 25 urlpatterns+=patterns('django.views.generic.simple',  26(r'^page/(?P<id>\d+)/$', 'redirect_to', {'url': '/page_new/%(id)s/'}},) 27 urlpatterns+=patterns('django.views.generic.list_detail',  28(r'^page/all/$', 'object_list', {'queryset':Pages.objects.all() }),) 29# default: {'paginate_by':'infinity' , 'page':'1',30# 'template_name':'app/model_list.html' }31 urlpatterns+=patterns('django.views.generic.list_detail',  32(r'^page/all/(?P<id>\d+)/$', 'object_detail', {'queryset':Pages.objects.all(), 'object _id':id}),) 33# default: {'paginate_by':'infinity' , 'page':'1',34# 'template_name':'app/model_detail.html' }35 urlpatterns+=patterns('django.views.generic.create_update',  36(r'^...$', 'create_object', {'model':SomeModel
  86. or
  87.  'form_class':SomeForm}),) 37# default: {'post_save_redirect':object.get_absolute_url(), 'login_required':False,38# 'template_name':'app/model_form.html' }39 urlpatterns+=patterns('django.views.generic.create_update',  40(r'^...$', 'update_object', {'model': / 'form_class':, 'object_id':SomeID}),) 41# default: {'post_save_redirect':object.get_absolute_url(), 'login_required':False,42# 'template_name':'app/model_form.html' }43 urlpatterns+=patterns('django.views.generic.create_update',  44(r'^...$', 'delete_object', {'model': / 'form_class':, 'object_id':SomeID}),) 45# default: {'post_save_redirect':object.get_absolute_url(), 'login_required':False,46# 'template_name':'app/model_confirm_delete.html' }4748# Parents are good for subdividing the work49 urlpatterns+=patterns('', # use include to add child url matchers: 50(r'^weblog/(?P<idName>\w+)/',include('mysite.app.url')), 51)52# in file app/url.py:53
  88. from
  89. django.conf.urls.defaults
  90. import
  91.  *54 urlpatterns=patterns('app.views', 55(r'^$', 'blog.index'),  56# "/weblog/me/" -> app.views.blog.index(request, idName='me')57(r'^post/(?P<postIndex>\d+)$', 'post.show'), 58# "/weblog/me/12" -> app.views.post.show(request, idName='me', postIndex='12')59(r'^details/$', 'blog.details', {'extraData', 'foo!'}) 60# "/weblog/details/" -> app.views.blog.details(request, idName='me', extraData='foo!')61(r'^post/(?P<pid>\d+)/comment/(?P<cid>\d+)/$', 'post.show', {'gotoComment', 'true'}, "w eblog-viewComment"),62# "/weblog/post/1/comment/1/" -> app.views.blog.details(request, idName='me', pid='1',cid='1', gotoComment='true')
  92. - 1 -
  93.  
  94. django_url_cheat.txtPage 2 of 2 Aug/2008
  95. 63# the template tag {% url weblog-viewComment pid=1,cid=1 %} returns "/weblog/post/1/comment/1/"64)6566# often you will write one function which has a default parameter to save code:67 urlpatterns=patterns('app.views', 68(r'^$', 'blog.index'),  69(r'^/(?P<postIndex>\d+)/$', 'blog.index')) 70
  96. def
  97.  index(request,postIndex='1') 71....7273# often we want to find a url that will execute a function with some parameters74# we would use {% url function args %} in a template. in code we would use:75
  98. from
  99. django.core.urlresolvers
  100. import
  101. reverse76 reverse(viewname,urlconf=
  102. None
  103. ,args=
  104. None
  105. ,kwargs=
  106. None
  107. )77
  108. def
  109.  myview(request): 78
  110. return
  111. HttpResponseRedirect(reverse('weblog-viewComment',args='pid=1,cid=1')) 7980# regular reference:81# . any char82# ^ start of string $ end of string83# * 0 or more of preceding + 1 or more of preceding84# ? 0 or 1 of preceding (?!..) matches when it doesnt match ..85# *? 0 or more, minimal match +? 1 or more, minimal match86# {m} exactly m of preceding {m,n} between m to n of preceding87# [..] eg. [abc],[a-z],[0-9a-z] [^..] matches if doesn't match [..]88# (..) groups what's inside (?=..) matches .. but doesn't consume it89# \d [0-9] (decimal digit) \D [^0-9] (non-digit)90# \w [a-zA-Z0-9_] (alphanumeric) \W [^a-zA-Z0-9_] (non-alphanumeric)91# \s [ \t\n\r\f\v] (whitespace) \S [^ \t\n\r\f\v] (non-whitespace)9293# Request and Response Object94
  112. def
  113.  index(request,index='1') 95 request.path# /weblog/me/ 96 request.method# either 'GET', 'POST', 'HEAD', ... 97 request.GET['someVarName'] # whatever it should be 98 request.GET['someVarName', 'default'] # if it doesn't exist then default. also for POST 99 request.POST['someVarName'] 100 request.R
  114.  
  115. EQUEST['someName'] # searches GET then FILES 101 request.COOKIES['attributeName'] 102 request.FILES['someFilename'] # request.POST does not have files 103# includes methods: read(num_bytes=...), chunk() and attrs: file_name, file_size104 request.META['someMetaName']  105# includes: CONTENT_LENGTH, CONTENT_TYPE, HTTP_ACCEPT_ENCODING, SERVER_PORT,106# HTTP_ACCEPT_LANGUAGE, HTTP_HOST, HTTP_REFERER, HTTP_USER_AGENT,107# QUERY_STR
  116.  
  117. ING, R
  118.  
  119. EMOTE_ADDR, R
  120.  
  121. EMOTE_HOST, R
  122.  
  123. EQUEST_METHOD, SERVER_NAME,108 request.user# object: django.contrib.auth.models.User 109 request.get_full_path() # includes any stuff after the last directory / 110 request.build_absolute_uri() # includes a http://www.. bit that is read from their side 111 request.is_ajax() # major ajax libraries send a signal that a query is for ajax
  124.  
  125. See also [http://www.djangoproject.com/documentation/templates/ templates for designers].
  126.  
  127.  
  128. django_forms_cheat.txtPage 1 of 2 Aug/2008
  129. 1# Simple Form with standard widgets.2
  130. from
  131. django
  132. import
  133. forms3
  134. class
  135.  ContactForm(forms.Form): 4 subject=forms.CharField(max_length=100) 5 message=forms.CharField() 6 sender=forms.EmailField() 7 cc_myself=forms.BooleanField(required=
  136. False
  137. ) # required=True by default89# Form with non-standard widget used10
  138. class
  139.  CommentForm(forms.Form): 11 name=forms.CharField(widget=forms.TextInput(attrs={'class':'special'})) 12 url=forms.URLField() 13 comment=forms.CharField(widget=forms.TextInput(attrs={'size':'40'})) 1415# Using forms16 f=ContactForm() # unbound - no data 17 data= {'subject': 'hello', 18'message': 'Hi there', 19'sender': 'foo@example.com', 20'cc_myself':
  140. True
  141. ,21'extra_field': 'foo'} 22 f=ContactForm(data) # bound - has data 23 f.is_valid() # validate 24 f.cleaned_data# returns a dictionary of the data - note: extra_field is dropped 2526# outputting html data all outputs automatically give labelled ids27 f.as_p() # renders as paragraphs 28 f.as_ul() # renders as dot-points (no <ul>) 29 f.as_table()  3031# Mapping forms to models32
  142. class
  143.  BlogForm(forms.ModelForm): 33# name = CharField(widget=forms.TextInput()) # you can override any field if you wish34
  144. class
  145.  Meta:35 model=Blog# where Article is something that inherits model.Model 36 fields= ('name',) # 'fields' specifies visible fields - so can't edit tagline, etc 37# exclude = ('tagline', 'bestEntry') # this also works, chose 'fields' or 'exclude'3839 form1=BlogForm() # just like a normal form. all normal form methods available 40 myblog=Blog.objects.get(id=1) 41 form2=BlogForm(instance=myblog) # just like normal binding 42 form2.save() # generate a model, then inserts it into db, or updates db 43# creating a new blog via a form44 b=Blog() 45 form3=BlogForm(request.POST,instance=b) 46 new_blog=form3.save(commit=
  146. False
  147. ) # generates a model, but doesn't insert into db47 new_blog.tagline= ... # since the form excluded this field, it must be filled before savin g48 new_blog.save() # saves the generated model 49 f.save_m2m() # saves many-to-many data - this is required only if you have commit=False 5051# Sample use of forms:52
  148. def
  149.  contact(request): 53
  150. if
  151. request.method== 'POST': 54 form=ContactForm(request.POST,request.FILES) 55# the second parameter is optional56
  152. if
  153. form.is_valid(): 57# Do form processing here...58
  154. return
  155. HttpResponseR
  156.  
  157. edirect('/url/on_success/') 59
  158. else
  159. :60 form=ContactForm() 61
  160. return
  161. render_to_response('contact.html', {'form':form}) 6263# you can write your own forms if you really want to:64# see django_template_cheat.txt
  162. - 1 -
  163. django_forms_cheat.txtPage 2 of 2 Aug/2008
  164. 65<form method="post"action=""> 66<dl> 67{%
  165. for
  166. field
  167. in
  168. form%}68<dt>{{field.label_tag}}{%
  169. if
  170. field.field.required%}*{%endif%}</dt> 69<dd>{{field}}</dd> 70{%
  171. if
  172. field.help_text%}<dd>{{field.help_text}}</dd>{%endif%} 71{%
  173. if
  174. field.errors%}<dd
  175. class
  176. ="myerrors">{{field.errors}}</dd>{%endif%} 72{%endfor%} 73</dl> 74<input type="submit" /> 75</form> 7677# Writing custom widgets means supplying a render function78
  177. from
  178. django.template.loader
  179. import
  180. render_to_string79
  181. class
  182.  CalendarWidget(forms.Widget):  80
  183. def
  184.  render(self,name,value,attrs=
  185. None
  186. ):81
  187. return
  188. render_to_string("widget/CalendarWidget.html",locals()) 82
  189. class
  190.  Media:83 css= {'all': ('pretty.css',)} 84 js= ('animations.js', 'actions.js') 8586
  191. class
  192.  BirthdayForm(forms.Form): 87 name=forms.CharField(max_length=100) 88 birthday=forms.DateField(widget=CalendarWidget) 8990# Field Type Reference91 BooleanField,CharField,ChoiceField,DateField,DateTimeField,DecimalField,  92 EmailField,FileField,FilePathField,FloatField,ImageField,IntegerField,  93 IPAddressField,MultipleChoiceField,NullBooleanField,RegexField,TimeField,  94 URLField9596# Field Argument Reference97 required,label,initial,widget,help_text,error_messages 9899# Widget Type Reference100 TextInput,PasswordInput,HiddenInput,FileInput,DateTimeInput,Textarea,  101 CheckboxInput,Select,SelectMultiple,RadioSelect,CheckboxSelectMultiple,  102 SplitDateTimeWidget
  193. django templates cheat sheet
  194. Ratings: (1)|Views: 12,906|Likes: 58
  195. Published by windoze007
  196. A concise 3 page cheat sheet of django's templates
  197. See more
  198.  
  199. django_template_cheat.txtPage 1 of 3 Aug/2008
  200. 1######################Rendition of django html templates2
  201. from
  202. django.template
  203. import
  204. Context,Template3 t=Template("My name is {{ my_name }}.") 4 c=Context({"my_name": "adrian"}) 5 t.render(c) # outputs "My name is Adrian" 6 c=Context({"my_name": "dolores"}) 7 t.render(c) # outputs "My name is dolores" 89 t=Template("My name is {{ person.first_name }}.") 10# when render meets a "." it will first try person["first_name"]11 c=Context({"person": {"first_name": "Joe", "last_name": "Johnson"}}) 12# then person.first_name13
  205. class
  206. PersonClass:
  207. pass
  208. 14 p=PersonClass() 15 p.first_name= "Joe" 16 c=Context({"person":p}) 17# then person.first_name()18
  209. class
  210. PersonClass2:19
  211. def
  212. first_name(self): 20
  213. return
  214. "Joe"21 p=PersonClass2() 22 c=Context({"person":p}) 23# then person[first_name]24 c=Context({"person": ["Samantha", "Ron", "Joe"], 'first_name': 2}) 2526 c=Context({"name": "david"}) 27 c['name'] 28
  215. del
  216. c['name'] 29 c['name']="jack" 3031#often you want modules to automatically add some variables into your context:32
  217. from
  218. django.template
  219. import
  220. RequestContext33
  221. def
  222. extraProcessor(request): 34
  223. return
  224. {'misc_extra_dictonary': 'here'} 35 c=RequestContext(request, {'name': 'david',},extraProcessor) 36#c will be populated with extra vars37#it will read the settings.py for TEMPLATE_CONTEXT_PROCESSORS and execute them all38#modules are under django.core.context_processors39#include auth:supporting users, debug, i18n, media, request:include request in context40#any function that takes a HttpR
  225.  
  226. equest and returns a dictionary can be used4142#often you want to load html pages:43
  227. from
  228. django.template.loader
  229. import
  230. get_template,select_template44 t=get_template(template_name) #load file or exception 45 t=select_template(template_name_list) #load first in list that exists 46#it will only load from TEMPLATE_DIRS in settings.py4748#often you want to save time not doing all this context, template stuff:49
  231. from
  232. django.template.loader
  233. import
  234. render_to_string50 rendered=render_to_string('my_template.html', { 'foo': 'bar' }) 5152#often you want to write your own filters and tags53#but right now you don't know what filters and tags are yet....5455######################Sample page base_generic.html56{# this is a comment #}5758{%load custom_module1 custom_module2%} 59{# loads custom python filter and tag modules#}6061<html> 62<head> 63<link rel="stylesheet"href="style.css" /> 64<title>{%block title%}David Website{%endblock%}</title>  65{# defining blocks will allow you to replace them later #}
  235. - 1 -
  236.  
  237. django_template_cheat.txtPage 2 of 3 Aug/2008
  238. 66</head> 67<body> 68<div id="sidebar"> 69{%block sidebar%} 70<ul> 71<li><a href="/">Home</a></li> 72<li><a href="/blog/">Blog</a></li> 73</ul> 74{%endblock%} 75</div> 7677<div id="content"> 78{%block content%}{%endblock%} 79</div> 8081<div id="disclaimer"> 82{%block disclaimer%}Copyright David{%endblock david%} 83{%include"legals/extraDisclaimer.html" %}  84{# renders that html into this page, passes current context #}85</div> 8687{%
  239. if
  240. wantDebug%}88{%debug%}{%enddebug%} 89{%endif%} 90</body> 91</html> 9293######################Sample page extended.html94{%extends"base_generic.html" %} 95{# if you render this page, it will render the base_generic.html #}96{# with each block that is defined here replacing that of the parent #}9798{%load custom_module2%} 99{# note that if your parent loads a module, you don't have it #}100101{%block title%}{{section.title}}{%endblock%} 102{# replace the block called "title" in base_generic #}103{# reads variable called section from the context #}104{# searches section["title"],section.title,section.title(),section[title] #}105{# in that exact order #}106107{# unreplaced blocks from base_generic.html, such as 'sidebar' are kept #}108109{%block content%} 110{%spaceless%} {# removes useless whitespace from the html below #} 111<h1>{{section.title}}</h1>  112{%
  241. for
  242. story
  243. in
  244. story_list%} 113<h2 color:{%cycle'red' 'blue' %}>  114{# each time the tag is read, it will output the next item #}115{{forloop.counter}}  116{# prints the loop counter #}117{# also: counter0, revcounter/0, first, last, parentloop.counter) #}118<a href="{{ story.get_absolute_url }}">  119{{story.headline|upper|capfirst}}  120{# the filter uppercases then captalises first letter #}121</a> 122</h2> 123<p>{{story.tease|cut:"\n"|truncatewords:"100" }}</p>  124{# the filter removes \n and then gets first 100 words #}125{{story.first_comment}}  126{# by default the variable is escaped #}127{# < > ' " & are converted into html character codes #}128129{{story.comment_list|first}}  130{{story.comment_list|join:", "}}
  245. - 2 -
  246. FERRIS STATE UNIVERSITY
  247. Tutorial
  248.  
  249. This tutorial will walk you through creating a simple API. If you haven't yet, be sure to read through the :doc:`introduction` and :doc:`getting_started` section. This assumes you have already created a new project- if not, head back to :doc:`getting_started` for instructions.
  250. A Simple “Posts” Service
  251.  
  252. To illustrate how quickly you can get a basic CRUD service up and running we'll create a simple "Posts" service. You could use service like this in a simple blog.
  253.  
  254. First we will create a posts folder inside of the app folder.
  255.  
  256. Note
  257.  
  258. For a refresher on how the new folder structure works, take a look at the :doc:`introduction` again. Also recall that python requires all folders you create in your project will need an empty __init__.py file inside of it. (Note: when Google allows us to use Python 3, we’ll no longer have to do this, c'mon, Google!)
  259.  
  260. Next we'll create the service file. The convention here is to use [service_name]_service.py, or in this case posts_service.py. By following the convention, Ferris' discovery utility will find this file and automatically load it for us. Inside this file we will define all the different methods we’d like our service to contain.
  261.  
  262. Before we start making methods to interact with Posts, however, we’ll need an actual Post model. We can accomplish this in two ways:
  263.  
  264.        Create a separate models.py file that contains the models we need.
  265.        Define the model inside our service file.
  266.  
  267. For the purpose of simplicity and because our Posts model is relatively simple, we’re going to go with inline option. While it may seem to fly in the face of traditional MVC conventions, we feel there's no need to make this any more complicated.
  268.  
  269. At this point you should have a file structure that looks like this:
  270.  
  271. /app
  272.     /posts
  273.         /__init__.py
  274.         /posts_service.py
  275.  
  276. Inside of posts_service.py we’ll need to import Ferris' Model class and the ndb module using the following lines:
  277.  
  278. from google.appengine.ext import ndb
  279. from ferris3 import Model
  280.  
  281. Note
  282.  
  283. Notice that we are importing ndb from the appengine module, not the ferris3 module. There is an ndb package inside the ferris3 module, but it’s not the one we want.
  284.  
  285. Ferris’ module names match the modules they supplement. So ferris.ndb supplements `google.appengine.ext.ndb, ferris.messages supplements protorpc.messages, ferris.endpoints supplements `endpoints, etc.
  286.  
  287. Now lets add our simple Posts model:
  288.  
  289. class Post(Model):
  290.    title = ndb.StringProperty()
  291.    content = ndb.TextProperty()
  292.  
  293. You'll notice that we're using App Engine's built-in ndb here- this is a pattern that permeates Ferris as we embrace and extend the underlying platform.
  294.  
  295. Now that we have a model let's create service to expose an API that allows CRUD operations on our Post model. First we'll need to import a few more things from Ferris. Augment your import statement to include auto_service, Service, and hvild, so it looks something like this:
  296.  
  297. from ferris3 import Model, Service, hvild, auto_service
  298.  
  299. Service will be the base class for our service and auto_service is a decorator that is used to automatically register and expose our service with Google Cloud Endpoints. Putting that all together our class definition looks like this:
  300.  
  301. @auto_service
  302. class PostsService(Service):
  303.  
  304. Now we get to hvild. Hvild is one of the more "magical" parts of Ferris and it will allow you to generate CRUD API methods like insert, get, update, delete, etc. quickly and painlessly. Those familiar with Ferris 2 will find it to be very similar to "scaffold". Lets give our posts service some basic functionality with the following lines:
  305.  
  306. list = hvild.list(Post)
  307. get = hvild.get(Post)
  308. delete = hvild.delete(Post)
  309. insert = hvild.insert(Post)
  310. update = hvild.update(Post)
  311.  
  312. That's it, just set your methods equal to their hvild counterparts and pass in the model that the methods manipulate (in this case Post).
  313.  
  314. To recap, our posts_service.py should look like this:
  315.  
  316. from google.appengine.ext import ndb
  317. from ferris3 import Model, Service, hvild, auto_service
  318.  
  319.  
  320. class Post(Model):
  321.    title = ndb.StringProperty()
  322.    content = ndb.TextProperty()
  323.  
  324.  
  325. @auto_service
  326. class PostsService(Service):
  327.    list = hvild.list(Post)
  328.    get = hvild.get(Post)
  329.    delete = hvild.delete(Post)
  330.    insert = hvild.insert(Post)
  331.    update = hvild.update(Post)
  332.  
  333. There are is another hvild method which will take just an ounce more effort to use: paginated_list. The only difference is that along with the model you must also pass in a limit parameter which will be the number of entities that appear on each page of the results. In our case, let's include 3 posts per page by adding these lines:
  334.  
  335. paginated_list = hvild.paginated_list(Post, limit=3)
  336.  
  337. Using the Google APIs Explorer
  338.  
  339. Now let's test these methods! First we're gonna need some posts in the datastore. We can put them there in one of two ways: We can either use the interactive console (located at localhost:8000) or we can use the insert method in the APIs Explorer that we just had hvild build for us. Either is fine, but we might as well use the Explorer just to get used to navigating through it.
  340.  
  341. Note
  342.  
  343. To get to the Explorer, navigate to http://localhost:8080/_ah/api/explorer. Remember, if you're using the launcher your ports may be different.
  344.  
  345. From here you should see "ferris API" in your list of available endpoints. If it doesn't show up, take a trip over to your terminal or error console to see what the error is and try to resolve it. Hopefully if you're following this guide it shouldn't be anything more than a typo.
  346.  
  347. Tip
  348.  
  349. If you get stuck reach out to us via the mailing list. Ferris has a fantastic community!
  350.  
  351. After clicking on "Ferris API", you will be taken to a new list showing all of the new services that we've just defined. Navigate to "ferris.posts.insert" to add some test posts.
  352.  
  353. From here, click inside the "Request body" input field and you will be given the option to choose a new property type add data for. We gave the Post model title and content properties, so you should see those along with a id property. A id will be generated automatically so we do not need to manually define it. Just give your post a title and some content and click the blue "Execute" button. You should receive a 200 OK notice of success along with a copy of the JSON data that describes the post you have just created.
  354.  
  355. Create a few posts, and then navigate back to the list of services and choose "ferris.posts.paginated_list". Ignore the fields for now and click "Execute". You should see some JSON showing some of the posts you made. If you made 4 or more, it will show only 3 of them, and after the third one it should give you a nextPageToken. This can be entered into the pageToken field to see the next page.
  356.  
  357. Feel free to test some of the other services. Some of them will concern just one particular post and will require the id of an item. Use it to delete, edit, or get a post.
  358. A Little More Complexity
  359.  
  360. So let's say you want to want to get a particular post but you don't know its key and all you remember about it is that its title was "Ferris 3 is Awesome". How would we create a service that allows us to get a post by its title? Unfortunately hvild cannot do this for us so we're going to have to write a few more than just a line or two. But don't fret! Ferris 3 will still make this a cinch!
  361.  
  362. First let's go ahead and import the entire ferris3 module. It isn't necessary to rename it, but shortening it to f3 will make things just a tiny bit quicker for us in the long run:
  363.  
  364. import ferris3 as f3
  365.  
  366. Now we're going to use some of the methods inside of the f3 module to create a model message for the Post model. Bear with me on this one it's gonna be tough:
  367.  
  368. PostMessage = f3.model_message(Post)
  369.  
  370. Huh, turns out that was totally painless. Creating messages for ndb Models in Ferris 3 is actually this simple. Model and List messages can be made in a snap. It's also possible to reduce the amount of information that your message will contain using the exclude parameter which we'll demonstrate later. For now let's get back to our "get by title" method.
  371.  
  372. Note
  373.  
  374. For more information about protorpc and messages see Google's documentation
  375.  
  376. When building a method we'll use a similar decorator as we did when we built the class:
  377.  
  378. @f3.auto_method()
  379.  
  380. auto_method takes a few optional arguments, namely returns and name. returns is the type of message that the service will return and name is the name that the service will appear under in the API explorer. If you leave out returns then ferris will just expect you to return nothing. If you leave out name ferris will just use the name of the function as the method name. In this case, we're going to return an instance of the PostMessage that we recently defined and we'll call our method get_by_title even though we could have left that out:
  381.  
  382. @f3.auto_method(returns=PostMessage, name="get_by_title")
  383.  
  384. Now we declare the method. We'll also name it get_by_title for consistency. The bare minimum parameters we need to give it are self and request. However, since we want to take in another parameter called title we'll need to add that as well. All together it should look like this:
  385.  
  386. def get_by_title(self, request, title=(str,)):
  387.  
  388. The syntax on the title parameter may look strange. Cloud endpoints needs to know the type of the parameter and this is our way of letting it know. The auto_method decorator will take care of the rest. We can also optionally give it a default value by doing title=(str, 'a default'), but in this case we want it to be a required field.
  389.  
  390. What's next is to use the Ferris 3 toolchain to get the Post we want, convert it into a PostMessage, and finally return it. First we'll show the complete code then break it down line-by-line:
  391.  
  392. query = Post.query(Post.title==title)
  393. post = query.get()
  394. if not post:
  395.     raise f3.NotFoundException()
  396. if not post.key.kind() == 'Post':
  397.     raise f3.InvalidRequestException()
  398. message = f3.messages.serialize(PostMessage, post)
  399. return message
  400.  
  401. Let's break this down:
  402.  
  403.        The first thing we do is create a standard ndb query using Post.query(Post.title==title).
  404.        Next we call query.get() which will fetch the first record from the query. This should be the post we're after.
  405.         The two if statements are sanity checks. First, we make sure we actually got an item back from the query, secondly, we make sure the item is actually a Post. (The kind check isn't strictly necessary here, however, you'll want to make sure you do this for any methods that use the id to get an item directly).
  406.         Finally, we'll serialize our Post object into a message using messages.serialize and return it.
  407.  
  408. For reference, the final code for the tutorial is:
  409.  
  410. from google.appengine.ext import ndb
  411. from ferris3 import Model, Service, hvild, auto_service
  412. import ferris3 as f3
  413.  
  414.  
  415. class Post(Model):
  416.    title = ndb.StringProperty()
  417.    content = ndb.TextProperty()
  418.  
  419.  
  420. PostMessage = f3.model_message(Post)
  421.  
  422.  
  423. @auto_service
  424. class PostsService(Service):
  425.    list = hvild.list(Post)
  426.    paginated_list = hvild.paginated_list(Post, limit=3)
  427.    get = hvild.get(Post)
  428.    delete = hvild.delete(Post)
  429.    insert = hvild.insert(Post)
  430.    update = hvild.update(Post)
  431.  
  432.    @f3.auto_method(returns=PostMessage, name="get_by_title")
  433.    def get_by_title(self, request, title=(str,)):
  434.        query = Post.query(Post.title==title)
  435.        post = query.get()
  436.        if not post:
  437.            raise f3.NotFoundException()
  438.        if not post.key.kind() == 'Post':
  439.            raise f3.InvalidRequestException()
  440.        message = f3.messages.serialize(PostMessage, post)
  441.        return message
  442.  
  443. Where to go from here
  444.  
  445. You've created your API backend so now you probably want to create some sort of front-end to talk to it. Most commonly you'll be writing a JavaScript client so head over to Google's documentation on Javascript API Clients. There's also guides for Android and iOS!
  446.  
  447. To dig deeper into what Ferris has to offer check out the :doc:`users_guide/index`.
  448. Mini_django.py An entire django app in a single file. Updated from here to use Django trunk.
  449. pico
  450. This started off to see what the absolutely smallest requirements needed to run a Django project. Run the pico_django.py with $ PYTHONPATH=. django-admin.py runserver 0.0.0.0:8000 --settings=pico_django and go to http://localhost:8000
  451. Or with uwsgi in production:
  452. $ uwsgi --http :8000 -M --pythonpath=. \
  453. --env DJANGO_SETTINGS_MODULE=pico_django \
  454. -w "django.core.handlers.wsgi:WSGIHandler()"
  455. pico_django.py
  456. from django.http import HttpResponse
  457. from django.conf.urls import url
  458.  
  459. DEBUG = True
  460. ROOT_URLCONF = 'pico_django'
  461. DATABASES = {'default': {}}
  462.  
  463.  
  464. def index(request, name):
  465.    return HttpResponse('Hello {name}!'.format(name=(name or 'World')))
  466.  
  467. urlpatterns = (
  468.    url(r'^(?P<name>\w+)?$', index)
  469. )
  470.  
  471. SECRET_KEY = "not so secret"
  472. mini
  473. Soon pico needed a little more spice, so it got some template loading and then because I'm lazy I made the new version directly runnable.
  474. Run the mini_django.py with $ python ./micro_django.py and go to http://localhost:8000/Foo
  475. mini_djanog.py
  476. '''
  477. Run this with `$ python ./miny_django.py runserver` and go to http://localhost:8000/
  478. '''
  479. import os
  480. import sys
  481. from django.conf import settings
  482.  
  483. from django.conf.urls import patterns
  484. from django.http import HttpResponse
  485.  
  486.  
  487. # this module
  488. me = os.path.splitext(os.path.split(__file__)[1])[0]
  489. # helper function to locate this dir
  490. here = lambda x: os.path.join(os.path.abspath(os.path.dirname(__file__)), x)
  491.  
  492. # SETTINGS
  493. DEBUG = True
  494. ROOT_URLCONF = me
  495. DATABASES = {'default': {}}  # required regardless of actual usage
  496. TEMPLATE_DIRS = (here('.'), )
  497. SECRET_KEY = 'so so secret'
  498.  
  499. if not settings.configured:
  500.     settings.configure(**locals())
  501.  
  502. # Settings must be configured before importing
  503. from django.views.decorators.csrf import csrf_exempt
  504.  
  505.  
  506. # VIEW
  507. @csrf_exempt
  508. def index(request):
  509.     return HttpResponse("Hello from mini_django.py")
  510.  
  511.  
  512. # URLS
  513. urlpatterns = patterns('', (r'^$', index))
  514.  
  515. if __name__ == '__main__':
  516.     # set the ENV
  517.     sys.path += (here('.'),)
  518.     # run the development server
  519.     from django.core import management
  520.     management.execute_from_command_line()
  521. Dependencies
  522. python
  523. django
  524. Install
  525. Install django
  526. get the code wget https://github.com/readevalprint/mini-django/raw/master/mini_django.py
  527. run it $ python ./mini_django.py
  528. open browser http://localhost.com/Foo
  529. License
  530. As-is. Public Domain. Don't blame me.
  531. Author
  532. Tim Watts (tim@readevalprint.com)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement