#55800
| # save this file in web2py/yourapp/modules/validators.py
# coding: utf-8
from gluon.validators import IS_EMAIL
class ANY(object):
"""
Verifies if at least ONE validation is valid!
Usage:
from validators import ANY
db.sometable.somefield.requires = ANY(IS_EMAIL(), IS_NOT_EMPTY(), ...)
For testing on shell:
>>> from validators import ANY
>>> ANY(IS_IN_SET(('a','b')), IS_EMAIL())('foo')
('foo', 'value not allowed')
>>> ANY([IS_IN_SET(['a','b']), IS_EMAIL()])('a')
('a', None)
ANY([IS_IN_SET(['a','b']), IS_EMAIL()])('foo@bar.com')
('foo@bar.com', None)
"""
def __init__(self, *validators):
self.validators = validators
def __call__(self, value):
# validates the value against each validator
results = [validator(value)[1] for validator in self.validators]
# check if all validations are invalid
if all(results):
# invalid, so return the first error message
return (value, results[0])
else:
# all valid
return (value, None)
class CUSTOM(object):
"""
you can use a function or a lambda
to validate or/and transform the field in the way you want
it is the same as "onvalidation" and "onsuccess" form callbacks
but it can be used per field in models or controller level
Usage:
from validators import CUSTOM
# the validate function should return the error_message or None
def begins_with_a(value):
if not value.startswith('a'):
return "Should start with a"
else:
return None
# the transform function should return a value
def to_upper(value):
return value.upper()
db.define_table("foo", Field("bar"))
db.foo.bar.requires = CUSTOM(begins_with_a, to_upper)
>>> CUSTOM(begins_with_a, to_upper)('apple')
('APPLE', None)
>>> CUSTOM(begins_with_a, to_upper)('orange')
('ORANGE', 'Should start with a')
"""
def __init__(self, validate=lambda value: None, transform=lambda value: value):
self.validate = validate
self.transform = transform
def __call__(self, value):
return(self.transform(value), self.validate(value))
class IS_EMAIL_LIST(object):
"""
To be used in textareas, users can include a comma
or space or line separated list of emails
Usage:
from validators import IS_EMAIL_LIST
db.define_table('emails',
Field('email_list','text', requires=IS_EMAIL_LIST())
)
>>> IS_EMAIL_LIST()('item1, item2@gmail.com')
("item1", "Email Item1 is invalid")
>>> IS_EMAIL_LIST()('item1@gmail.com, item2@gmail.com')
('item1@gmail.com, item2@gmail.com', None)
Optionally you can return a Python List if your field
is a list:string
"""
def __init__(self, error_message="Email %s is invalid", sep=",", ret='str'):
self.error_message = error_message
self.sep = sep
self.ret = 'str' or 'list'
def __call__(self, value):
emails = value.strip().replace('\n','').replace('\t','').split(self.sep)
for email in emails:
email = email.strip()
if IS_EMAIL()(email)[1] != None:
return (email, self.error_message % email)
return (value if self.ret == 'str' else emails, None)
|
Expand
Collapse
(111 lines)
https://snipt.net/embed/f761ce8918909c393536df55efcd8676/
https://snipt.net/raw/f761ce8918909c393536df55efcd8676/
f761ce8918909c393536df55efcd8676
python
Python
111
2013-05-20T04:24:45
True
True
Feb 14, 2013 at 10:18 PM
/api/public/snipt/55800/
more-web2py-custom-validators
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><a href="#L-1"> 1</a>
<a href="#L-2"> 2</a>
<a href="#L-3"> 3</a>
<a href="#L-4"> 4</a>
<a href="#L-5"> 5</a>
<a href="#L-6"> 6</a>
<a href="#L-7"> 7</a>
<a href="#L-8"> 8</a>
<a href="#L-9"> 9</a>
<a href="#L-10"> 10</a>
<a href="#L-11"> 11</a>
<a href="#L-12"> 12</a>
<a href="#L-13"> 13</a>
<a href="#L-14"> 14</a>
<a href="#L-15"> 15</a>
<a href="#L-16"> 16</a>
<a href="#L-17"> 17</a>
<a href="#L-18"> 18</a>
<a href="#L-19"> 19</a>
<a href="#L-20"> 20</a>
<a href="#L-21"> 21</a>
<a href="#L-22"> 22</a>
<a href="#L-23"> 23</a>
<a href="#L-24"> 24</a>
<a href="#L-25"> 25</a>
<a href="#L-26"> 26</a>
<a href="#L-27"> 27</a>
<a href="#L-28"> 28</a>
<a href="#L-29"> 29</a>
<a href="#L-30"> 30</a>
<a href="#L-31"> 31</a>
<a href="#L-32"> 32</a>
<a href="#L-33"> 33</a>
<a href="#L-34"> 34</a>
<a href="#L-35"> 35</a>
<a href="#L-36"> 36</a>
<a href="#L-37"> 37</a>
<a href="#L-38"> 38</a>
<a href="#L-39"> 39</a>
<a href="#L-40"> 40</a>
<a href="#L-41"> 41</a>
<a href="#L-42"> 42</a>
<a href="#L-43"> 43</a>
<a href="#L-44"> 44</a>
<a href="#L-45"> 45</a>
<a href="#L-46"> 46</a>
<a href="#L-47"> 47</a>
<a href="#L-48"> 48</a>
<a href="#L-49"> 49</a>
<a href="#L-50"> 50</a>
<a href="#L-51"> 51</a>
<a href="#L-52"> 52</a>
<a href="#L-53"> 53</a>
<a href="#L-54"> 54</a>
<a href="#L-55"> 55</a>
<a href="#L-56"> 56</a>
<a href="#L-57"> 57</a>
<a href="#L-58"> 58</a>
<a href="#L-59"> 59</a>
<a href="#L-60"> 60</a>
<a href="#L-61"> 61</a>
<a href="#L-62"> 62</a>
<a href="#L-63"> 63</a>
<a href="#L-64"> 64</a>
<a href="#L-65"> 65</a>
<a href="#L-66"> 66</a>
<a href="#L-67"> 67</a>
<a href="#L-68"> 68</a>
<a href="#L-69"> 69</a>
<a href="#L-70"> 70</a>
<a href="#L-71"> 71</a>
<a href="#L-72"> 72</a>
<a href="#L-73"> 73</a>
<a href="#L-74"> 74</a>
<a href="#L-75"> 75</a>
<a href="#L-76"> 76</a>
<a href="#L-77"> 77</a>
<a href="#L-78"> 78</a>
<a href="#L-79"> 79</a>
<a href="#L-80"> 80</a>
<a href="#L-81"> 81</a>
<a href="#L-82"> 82</a>
<a href="#L-83"> 83</a>
<a href="#L-84"> 84</a>
<a href="#L-85"> 85</a>
<a href="#L-86"> 86</a>
<a href="#L-87"> 87</a>
<a href="#L-88"> 88</a>
<a href="#L-89"> 89</a>
<a href="#L-90"> 90</a>
<a href="#L-91"> 91</a>
<a href="#L-92"> 92</a>
<a href="#L-93"> 93</a>
<a href="#L-94"> 94</a>
<a href="#L-95"> 95</a>
<a href="#L-96"> 96</a>
<a href="#L-97"> 97</a>
<a href="#L-98"> 98</a>
<a href="#L-99"> 99</a>
<a href="#L-100">100</a>
<a href="#L-101">101</a>
<a href="#L-102">102</a>
<a href="#L-103">103</a>
<a href="#L-104">104</a>
<a href="#L-105">105</a>
<a href="#L-106">106</a>
<a href="#L-107">107</a>
<a href="#L-108">108</a>
<a href="#L-109">109</a>
<a href="#L-110">110</a>
<a href="#L-111">111</a></pre></div></td><td class="code"><div class="highlight"><pre><span id="L-1"><a name="L-1"></a><span class="c"># save this file in web2py/yourapp/modules/validators.py</span>
</span><span id="L-2"><a name="L-2"></a>
</span><span id="L-3"><a name="L-3"></a><span class="c"># coding: utf-8</span>
</span><span id="L-4"><a name="L-4"></a>
</span><span id="L-5"><a name="L-5"></a><span class="kn">from</span> <span class="nn">gluon.validators</span> <span class="kn">import</span> <span class="n">IS_EMAIL</span>
</span><span id="L-6"><a name="L-6"></a>
</span><span id="L-7"><a name="L-7"></a>
</span><span id="L-8"><a name="L-8"></a><span class="k">class</span> <span class="nc">ANY</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
</span><span id="L-9"><a name="L-9"></a> <span class="sd">"""</span>
</span><span id="L-10"><a name="L-10"></a><span class="sd"> Verifies if at least ONE validation is valid!</span>
</span><span id="L-11"><a name="L-11"></a><span class="sd"> Usage:</span>
</span><span id="L-12"><a name="L-12"></a><span class="sd"> from validators import ANY</span>
</span><span id="L-13"><a name="L-13"></a><span class="sd"> db.sometable.somefield.requires = ANY(IS_EMAIL(), IS_NOT_EMPTY(), ...)</span>
</span><span id="L-14"><a name="L-14"></a>
</span><span id="L-15"><a name="L-15"></a><span class="sd"> For testing on shell:</span>
</span><span id="L-16"><a name="L-16"></a><span class="sd"> >>> from validators import ANY</span>
</span><span id="L-17"><a name="L-17"></a><span class="sd"> >>> ANY(IS_IN_SET(('a','b')), IS_EMAIL())('foo')</span>
</span><span id="L-18"><a name="L-18"></a><span class="sd"> ('foo', 'value not allowed')</span>
</span><span id="L-19"><a name="L-19"></a><span class="sd"> >>> ANY([IS_IN_SET(['a','b']), IS_EMAIL()])('a')</span>
</span><span id="L-20"><a name="L-20"></a><span class="sd"> ('a', None)</span>
</span><span id="L-21"><a name="L-21"></a><span class="sd"> ANY([IS_IN_SET(['a','b']), IS_EMAIL()])('foo@bar.com')</span>
</span><span id="L-22"><a name="L-22"></a><span class="sd"> ('foo@bar.com', None)</span>
</span><span id="L-23"><a name="L-23"></a><span class="sd"> """</span>
</span><span id="L-24"><a name="L-24"></a>
</span><span id="L-25"><a name="L-25"></a> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">validators</span><span class="p">):</span>
</span><span id="L-26"><a name="L-26"></a> <span class="bp">self</span><span class="o">.</span><span class="n">validators</span> <span class="o">=</span> <span class="n">validators</span>
</span><span id="L-27"><a name="L-27"></a>
</span><span id="L-28"><a name="L-28"></a> <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
</span><span id="L-29"><a name="L-29"></a> <span class="c"># validates the value against each validator</span>
</span><span id="L-30"><a name="L-30"></a> <span class="n">results</span> <span class="o">=</span> <span class="p">[</span><span class="n">validator</span><span class="p">(</span><span class="n">value</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">validator</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">validators</span><span class="p">]</span>
</span><span id="L-31"><a name="L-31"></a> <span class="c"># check if all validations are invalid</span>
</span><span id="L-32"><a name="L-32"></a> <span class="k">if</span> <span class="nb">all</span><span class="p">(</span><span class="n">results</span><span class="p">):</span>
</span><span id="L-33"><a name="L-33"></a> <span class="c"># invalid, so return the first error message</span>
</span><span id="L-34"><a name="L-34"></a> <span class="k">return</span> <span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span><span id="L-35"><a name="L-35"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-36"><a name="L-36"></a> <span class="c"># all valid</span>
</span><span id="L-37"><a name="L-37"></a> <span class="k">return</span> <span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
</span><span id="L-38"><a name="L-38"></a>
</span><span id="L-39"><a name="L-39"></a>
</span><span id="L-40"><a name="L-40"></a>
</span><span id="L-41"><a name="L-41"></a><span class="k">class</span> <span class="nc">CUSTOM</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
</span><span id="L-42"><a name="L-42"></a> <span class="sd">"""</span>
</span><span id="L-43"><a name="L-43"></a><span class="sd"> you can use a function or a lambda</span>
</span><span id="L-44"><a name="L-44"></a><span class="sd"> to validate or/and transform the field in the way you want</span>
</span><span id="L-45"><a name="L-45"></a><span class="sd"> it is the same as "onvalidation" and "onsuccess" form callbacks</span>
</span><span id="L-46"><a name="L-46"></a><span class="sd"> but it can be used per field in models or controller level</span>
</span><span id="L-47"><a name="L-47"></a><span class="sd"> Usage:</span>
</span><span id="L-48"><a name="L-48"></a><span class="sd"> from validators import CUSTOM</span>
</span><span id="L-49"><a name="L-49"></a>
</span><span id="L-50"><a name="L-50"></a><span class="sd"> # the validate function should return the error_message or None</span>
</span><span id="L-51"><a name="L-51"></a><span class="sd"> def begins_with_a(value):</span>
</span><span id="L-52"><a name="L-52"></a><span class="sd"> if not value.startswith('a'):</span>
</span><span id="L-53"><a name="L-53"></a><span class="sd"> return "Should start with a"</span>
</span><span id="L-54"><a name="L-54"></a><span class="sd"> else:</span>
</span><span id="L-55"><a name="L-55"></a><span class="sd"> return None</span>
</span><span id="L-56"><a name="L-56"></a><span class="sd"> </span>
</span><span id="L-57"><a name="L-57"></a><span class="sd"> # the transform function should return a value</span>
</span><span id="L-58"><a name="L-58"></a><span class="sd"> def to_upper(value):</span>
</span><span id="L-59"><a name="L-59"></a><span class="sd"> return value.upper()</span>
</span><span id="L-60"><a name="L-60"></a>
</span><span id="L-61"><a name="L-61"></a><span class="sd"> db.define_table("foo", Field("bar"))</span>
</span><span id="L-62"><a name="L-62"></a><span class="sd"> db.foo.bar.requires = CUSTOM(begins_with_a, to_upper)</span>
</span><span id="L-63"><a name="L-63"></a><span class="sd"> </span>
</span><span id="L-64"><a name="L-64"></a><span class="sd"> >>> CUSTOM(begins_with_a, to_upper)('apple')</span>
</span><span id="L-65"><a name="L-65"></a><span class="sd"> ('APPLE', None)</span>
</span><span id="L-66"><a name="L-66"></a><span class="sd"> >>> CUSTOM(begins_with_a, to_upper)('orange')</span>
</span><span id="L-67"><a name="L-67"></a><span class="sd"> ('ORANGE', 'Should start with a')</span>
</span><span id="L-68"><a name="L-68"></a>
</span><span id="L-69"><a name="L-69"></a><span class="sd"> """</span>
</span><span id="L-70"><a name="L-70"></a> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">validate</span><span class="o">=</span><span class="k">lambda</span> <span class="n">value</span><span class="p">:</span> <span class="bp">None</span><span class="p">,</span> <span class="n">transform</span><span class="o">=</span><span class="k">lambda</span> <span class="n">value</span><span class="p">:</span> <span class="n">value</span><span class="p">):</span>
</span><span id="L-71"><a name="L-71"></a> <span class="bp">self</span><span class="o">.</span><span class="n">validate</span> <span class="o">=</span> <span class="n">validate</span>
</span><span id="L-72"><a name="L-72"></a> <span class="bp">self</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="n">transform</span>
</span><span id="L-73"><a name="L-73"></a>
</span><span id="L-74"><a name="L-74"></a> <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
</span><span id="L-75"><a name="L-75"></a> <span class="k">return</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">validate</span><span class="p">(</span><span class="n">value</span><span class="p">))</span>
</span><span id="L-76"><a name="L-76"></a>
</span><span id="L-77"><a name="L-77"></a>
</span><span id="L-78"><a name="L-78"></a><span class="k">class</span> <span class="nc">IS_EMAIL_LIST</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
</span><span id="L-79"><a name="L-79"></a> <span class="sd">"""</span>
</span><span id="L-80"><a name="L-80"></a><span class="sd"> To be used in textareas, users can include a comma</span>
</span><span id="L-81"><a name="L-81"></a><span class="sd"> or space or line separated list of emails</span>
</span><span id="L-82"><a name="L-82"></a><span class="sd"> Usage:</span>
</span><span id="L-83"><a name="L-83"></a><span class="sd"> from validators import IS_EMAIL_LIST</span>
</span><span id="L-84"><a name="L-84"></a><span class="sd"> db.define_table('emails',</span>
</span><span id="L-85"><a name="L-85"></a><span class="sd"> Field('email_list','text', requires=IS_EMAIL_LIST())</span>
</span><span id="L-86"><a name="L-86"></a><span class="sd"> )</span>
</span><span id="L-87"><a name="L-87"></a><span class="sd"> </span>
</span><span id="L-88"><a name="L-88"></a><span class="sd"> >>> IS_EMAIL_LIST()('item1, item2@gmail.com')</span>
</span><span id="L-89"><a name="L-89"></a><span class="sd"> ("item1", "Email Item1 is invalid")</span>
</span><span id="L-90"><a name="L-90"></a><span class="sd"> >>> IS_EMAIL_LIST()('item1@gmail.com, item2@gmail.com')</span>
</span><span id="L-91"><a name="L-91"></a><span class="sd"> ('item1@gmail.com, item2@gmail.com', None)</span>
</span><span id="L-92"><a name="L-92"></a><span class="sd"> </span>
</span><span id="L-93"><a name="L-93"></a><span class="sd"> Optionally you can return a Python List if your field</span>
</span><span id="L-94"><a name="L-94"></a><span class="sd"> is a list:string</span>
</span><span id="L-95"><a name="L-95"></a><span class="sd"> """</span>
</span><span id="L-96"><a name="L-96"></a> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">error_message</span><span class="o">=</span><span class="s">"Email </span><span class="si">%s</span><span class="s"> is invalid"</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s">","</span><span class="p">,</span> <span class="n">ret</span><span class="o">=</span><span class="s">'str'</span><span class="p">):</span>
</span><span id="L-97"><a name="L-97"></a> <span class="bp">self</span><span class="o">.</span><span class="n">error_message</span> <span class="o">=</span> <span class="n">error_message</span>
</span><span id="L-98"><a name="L-98"></a> <span class="bp">self</span><span class="o">.</span><span class="n">sep</span> <span class="o">=</span> <span class="n">sep</span>
</span><span id="L-99"><a name="L-99"></a> <span class="bp">self</span><span class="o">.</span><span class="n">ret</span> <span class="o">=</span> <span class="s">'str'</span> <span class="ow">or</span> <span class="s">'list'</span>
</span><span id="L-100"><a name="L-100"></a>
</span><span id="L-101"><a name="L-101"></a> <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
</span><span id="L-102"><a name="L-102"></a> <span class="n">emails</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span><span class="s">''</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'</span><span class="se">\t</span><span class="s">'</span><span class="p">,</span><span class="s">''</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sep</span><span class="p">)</span>
</span><span id="L-103"><a name="L-103"></a> <span class="k">for</span> <span class="n">email</span> <span class="ow">in</span> <span class="n">emails</span><span class="p">:</span>
</span><span id="L-104"><a name="L-104"></a> <span class="n">email</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span><span id="L-105"><a name="L-105"></a> <span class="k">if</span> <span class="n">IS_EMAIL</span><span class="p">()(</span><span class="n">email</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="bp">None</span><span class="p">:</span>
</span><span id="L-106"><a name="L-106"></a> <span class="k">return</span> <span class="p">(</span><span class="n">email</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">error_message</span> <span class="o">%</span> <span class="n">email</span><span class="p">)</span>
</span><span id="L-107"><a name="L-107"></a> <span class="k">return</span> <span class="p">(</span><span class="n">value</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">ret</span> <span class="o">==</span> <span class="s">'str'</span> <span class="k">else</span> <span class="n">emails</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
</span><span id="L-108"><a name="L-108"></a>
</span><span id="L-109"><a name="L-109"></a>
</span><span id="L-110"><a name="L-110"></a>
</span><span id="L-111"><a name="L-111"></a>
</span></pre></div>
</td></tr></table>
python, web2py
#54112
Como utilizar o módulo logging do Python em seus apps web2py.
Este video é parte da aula 4 do cursodepython.com.br
https://snipt.net/embed/b5c474a128a978d6c5bb0faaf677501e/
https://snipt.net/raw/b5c474a128a978d6c5bb0faaf677501e/
b5c474a128a978d6c5bb0faaf677501e
markdown
Markdown
7
2013-05-20T04:24:37
True
True
Jan 21, 2013 at 12:29 AM
/api/public/snipt/54112/
gravando-logs-de-aplicativos-web2py
<p>Como utilizar o módulo <code>logging</code> do Python em seus apps web2py.</p>
<p><iframe src="https://player.vimeo.com/video/57826628" width="700" height="400" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></p>
<p>Este video é parte da aula 4 do <a href="http://www.cursodepython.com.br">cursodepython.com.br</a></p>
expand, python, snipt-expand, web2py
#53226
This post is the beginning of a KISS tag, a place where I will put all the "over complications" I find on codes that I work on, or even to comment on my own mistakes.
WTF?
Today I was working on a Django reports app and I saw this code:
result = reduce(lambda x, y: x + y, \
[i.thing.price for i in \
ModelObject.objects.filter(created_at__gte=date)])
At the first look, specially because of the use of reduce I thought it was a complicated issue to solve.
2 seconds after I realized.
Why using reduce for sum when Python already has the built in sum function?
result = sum([i.thing.price for i in ModelObject.objects.filter(created_at__gte=date)])
Well Python gives us powerful builtins so just use this!
The other problem here is the memory usage of the above solution, it will first get the objects list from filter() and after that it will iterate one by one, doing a field lookup to take the price and return a new list with values to sum.
It can kill your server!
On this case things can be done in a better way! we are talking about Django! and even I am being a Django ORM hater I know that it has some cool things like this one:
Django ORM aggregations
from django.db.models import Count
queryset = ModelObject.objects.filter(created_at__gte=date)
aggregation = queryset.aggregate(price=Sum('thing__price'))
result = aggregation.get('price', 0)
On the above code, the aggregation Sum will translate in to a SQL command and the sum will be performed on the database side! much better
I really do not like the Django ORM syntax, also I hate the way I bind the objects, maybe because I am used to use the wonderful DAL
I prefer to refer to data as data, I mean, data as Rows not data as objects.
But in cases I am working with Django, I think the best is to use its powerful tools!
Keep It Simple Stupid!
Expand
Collapse
(48 lines)
https://snipt.net/embed/eafb8baf62bdfc215015038cef734c77/
https://snipt.net/raw/eafb8baf62bdfc215015038cef734c77/
eafb8baf62bdfc215015038cef734c77
markdown
Markdown
48
2013-05-20T22:04:36
True
True
Jan 11, 2013 at 08:31 PM
/api/public/snipt/53226/
kiss-use-the-built-in-sum-instead-of-reduce-to-aggregate-over-a-list-comprehension
<p>This post is the beginning of a <code>KISS</code> tag, a place where I will put all the "over complications" I find on codes that I work on, or even to comment on my own mistakes.</p>
<h1>WTF?</h1>
<p>Today I was working on a Django reports app and I saw this code:</p>
<pre><code>result = reduce(lambda x, y: x + y, \
[i.thing.price for i in \
ModelObject.objects.filter(created_at__gte=date)])
</code></pre>
<p>At the first look, specially because of the use of <code>reduce</code> I thought it was a complicated issue to solve.</p>
<p>2 seconds after I realized.</p>
<h1>Why using reduce for sum when Python already has the built in sum function?</h1>
<pre><code>result = sum([i.thing.price for i in ModelObject.objects.filter(created_at__gte=date)])
</code></pre>
<blockquote>
<p>Well Python gives us powerful builtins so just use this!</p>
</blockquote>
<p>The other problem here is the memory usage of the above solution, it will first get the objects list from filter() and after that it will iterate one by one, doing a field lookup to take the <code>price</code> and return a new list with values to sum.</p>
<p><strong>It can kill your server!</strong></p>
<blockquote>
<p>On this case things can be done in a better way! we are talking about Django! and even I am being a Django ORM hater I know that it has some cool things like this one:</p>
</blockquote>
<h1>Django ORM aggregations</h1>
<pre><code>from django.db.models import Count
queryset = ModelObject.objects.filter(created_at__gte=date)
aggregation = queryset.aggregate(price=Sum('thing__price'))
result = aggregation.get('price', 0)
</code></pre>
<p>On the above code, the aggregation <code>Sum</code> will translate in to a SQL command and the sum will be performed on the database side! much better</p>
<blockquote>
<p>I really do not like the Django ORM syntax, also I hate the way I bind the objects, maybe because I am used to use the wonderful DAL
I prefer to refer to data as data, I mean, data as Rows not data as objects.
But in cases I am working with Django, I think the best is to use its powerful tools!</p>
</blockquote>
<p><strong>Keep It Simple Stupid!</strong></p>
django, kiss, python
#53097
Recently I tried many ways to add a simple record counter on Django admin home page, I needed it to look like this:

I have tried django admin tools, overwriting the _meta on admin.py but the probleam with admin tools is that it installed a lot of aditional stuff I did not like to use, and
the problem with other approaches was because I needed it to be dynamic. Overwriting the __meta seemed to be the right way but is binded only one time, and no updates done until the app restarts.
My friend Fernando Macedo did it the right way!
specialize the string type to add your desired dynamic behavior
from django.db import models
class VerboseName(str):
def __init__(self, func):
self.func = func
def decode(self, encoding, erros):
return self.func().decode(encoding, erros)
class UsedCoupons(models.Model):
name = models.CharField(max_length=10)
class Meta:
verbose_name_plural = VerboseName(lambda: u"Used Coupons (%d)" % UsedCoupons.objects.count())
And this gives us a lesson, try to solve your problems in pure Python before looking for tricks or ready solutions. (wow it is a dynamic language!)
Expand
Collapse
(32 lines)
https://snipt.net/embed/14f04d38831e27ec0e7cbbe84f1d0837/
https://snipt.net/raw/14f04d38831e27ec0e7cbbe84f1d0837/
14f04d38831e27ec0e7cbbe84f1d0837
markdown
Markdown
32
2013-05-21T01:14:03
True
True
Jan 10, 2013 at 09:28 AM
/api/public/snipt/53097/
add-a-counter-on-django-admin-home-page
<p>Recently I tried <a href="http://stackoverflow.com/questions/14217325/add-a-counter-to-django-admin-home">many ways</a> to add a simple record counter on Django admin home page, I needed it to look like this:</p>
<p><img src="http://i.stack.imgur.com/ZsDsX.png" alt="counter" /></p>
<p>I have tried django admin tools, overwriting the _meta on admin.py but the probleam with admin tools is that it installed a lot of aditional stuff I did not like to use, and
the problem with other approaches was because I needed it to be dynamic. Overwriting the __meta seemed to be the right way but is binded only one time, and no updates done until the app restarts.</p>
<p>My friend <a href="http://stackoverflow.com/users/585592/fernando-macedo">Fernando Macedo</a> did it the right way!</p>
<p><strong>specialize the string type to add your desired dynamic behavior</strong></p>
<pre><code>from django.db import models
class VerboseName(str):
def __init__(self, func):
self.func = func
def decode(self, encoding, erros):
return self.func().decode(encoding, erros)
class UsedCoupons(models.Model):
name = models.CharField(max_length=10)
class Meta:
verbose_name_plural = VerboseName(lambda: u"Used Coupons (%d)" % UsedCoupons.objects.count())
</code></pre>
<p>And this gives us a lesson, try to solve your problems in pure Python before looking for tricks or ready solutions. (wow it is a dynamic language!)</p>
django, pyplanet, python
#52746
Programmatically check if South has migrations to run.
from south import migration
from south.models import MigrationHistory
apps = list(migration.all_migrations())
applied_migrations = MigrationHistory.objects.filter(app_name__in=[app.app_label() for app in apps])
applied_migrations = ['%s.%s' % (mi.app_name,mi.migration) for mi in applied_migrations]
num_new_migrations = 0
for app in apps:
for migration in app:
if migration.app_label() + "." + migration.name() not in applied_migrations:
num_new_migrations = num_new_migrations + 1
return num_new_migrations
It can be wrapped in to a function and can be used to monitor South state in admin.
Based on south.management.commands.migrate and some C/P from stack overflow
Expand
Collapse
(22 lines)
https://snipt.net/embed/55409627f74da96ea92b6d25df30fff1/
https://snipt.net/raw/55409627f74da96ea92b6d25df30fff1/
55409627f74da96ea92b6d25df30fff1
markdown
Markdown
22
2013-05-20T04:24:40
True
True
Jan 03, 2013 at 11:48 PM
/api/public/snipt/52746/
programatically-check-if-you-south-have-migrations-to-run
<p>Programmatically check if South has migrations to run.</p>
<pre><code>from south import migration
from south.models import MigrationHistory
apps = list(migration.all_migrations())
applied_migrations = MigrationHistory.objects.filter(app_name__in=[app.app_label() for app in apps])
applied_migrations = ['%s.%s' % (mi.app_name,mi.migration) for mi in applied_migrations]
num_new_migrations = 0
for app in apps:
for migration in app:
if migration.app_label() + "." + migration.name() not in applied_migrations:
num_new_migrations = num_new_migrations + 1
return num_new_migrations
</code></pre>
<p>It can be wrapped in to a function and can be used to monitor South state in admin.</p>
<p>Based on south.management.commands.migrate and some C/P from stack overflow</p>
django, pyplanet, shell, south
#52692
When Python runs a script and an uncatched exception is raised, a traceback is printed and the script is terminated. Python2.1 has introduced sys.excepthook, which can be used to override the handling of uncaught exceptions. This allows to automatically start the debugger on an unexpected exception, even if python is not running in interactive mode.
# code snippet, to be included in 'sitecustomize.py'
import sys
def info(type, value, tb):
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
# we are in interactive mode or we don't have a tty-like
# device, so we call the default hook
sys.__excepthook__(type, value, tb)
else:
import traceback, pdb
# we are NOT in interactive mode, print the exception...
traceback.print_exception(type, value, tb)
print
# ...then start the debugger in post-mortem mode.
pdb.pm()
sys.excepthook = info
The above snipper can be easily included in your editor snippets and you can set it on top of your files, or even better you can include on your sitecustomize.py
NOTE:
Use: import pywin.debugger and pywin.debugger.pm()
if you want a gui
Based on this stacj overflow thread. http://code.activestate.com/recipes/65287/
Expand
Collapse
(30 lines)
https://snipt.net/embed/52df57741c1f88f2365c26c5f5831b96/
https://snipt.net/raw/52df57741c1f88f2365c26c5f5831b96/
52df57741c1f88f2365c26c5f5831b96
markdown
Markdown
30
2013-05-20T04:24:46
True
True
Jan 02, 2013 at 10:41 PM
/api/public/snipt/52692/
automatically-start-the-debugger-on-an-exception
<p>When Python runs a script and an uncatched exception is raised, a traceback is printed and the script is terminated. Python2.1 has introduced sys.excepthook, which can be used to override the handling of uncaught exceptions. This allows to automatically start the debugger on an unexpected exception, even if python is not running in interactive mode.</p>
<pre><code># code snippet, to be included in 'sitecustomize.py'
import sys
def info(type, value, tb):
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
# we are in interactive mode or we don't have a tty-like
# device, so we call the default hook
sys.__excepthook__(type, value, tb)
else:
import traceback, pdb
# we are NOT in interactive mode, print the exception...
traceback.print_exception(type, value, tb)
print
# ...then start the debugger in post-mortem mode.
pdb.pm()
sys.excepthook = info
</code></pre>
<p>The above snipper can be easily included in your editor snippets and you can set it on top of your files, or even better you can include on your <code>sitecustomize.py</code></p>
<blockquote>
<p>NOTE:
Use: <code>import pywin.debugger</code> and <code>pywin.debugger.pm()</code>
if you want a gui</p>
</blockquote>
<p>Based on this stacj overflow thread. http://code.activestate.com/recipes/65287/</p>
pdb, pyplanet, python
#52591
https://github.com/rochacbruno/dopy
dopy
____ _
| _ \ ___ _ __ _ _| |
| | | |/ _ \ | '_ \| | | | |
| |_| | (_) || |_) | |_| |_|
|____/ \___(_) .__/ \__, (_)
|_| |___/
To Do list on Command Line Interface
Manage to-do list on a shell based simple interface and stores your to-do locally on a sqlite database
optionally use your Dropbox to store the database

Instalation
pip install dopy
or
git clone https://github.com/rochacbruno/dopy
cd dopy
python setup.py install
or
git clone https://github.com/rochacbruno/dopy
chmod +x dopy/dopy/do.py
sudo ln -s path/to/dopy/dopy/do.py /bin/dopy
Maybe the pip option will not be working for a while
Usage
____ _
| _ \ ___ _ __ _ _| |
| | | |/ _ \ | '_ \| | | | |
| |_| | (_) || |_) | |_| |_|
|____/ \___(_) .__/ \__, (_)
|_| |___/
Usage:
do.py [--use=<db>] [--args]
do.py add <name> [<tag>] [<status>] [--reminder=<reminder>] [--use=<db>] [--args]
do.py done <id> [--use=<db>] [--args]
do.py ls [--all] [--tag=<tag>] [--status=<status>] [--search=<term>] [--date=<date>] [--month=<month>] [--day=<day>] [--year=<year>] [--use=<db>] [--args]
do.py rm <id> [--use=<db>] [--args]
do.py get <id> [--use=<db>] [--args]
do.py note <id> [--use=<db>] [--rm=<noteindex>] [--args]
do.py show <id> [--use=<db>] [--args]
do.py note <id> <note> [--use=<db>] [--args]
do.py export <path> [--format=<format>] [--use=<db>] [--args]
do.py setpath <path> [--args]
do.py use <db> [--args]
do.py -h | --help [--args]
do.py --version [--args]
do.py --args
Options:
-h --help Show this screen.
--version Show version.
--args Show args.
to enter in SHELL mode
python do.py or simply dopy if installed
Add a new task
dopy <name> <tag> <status> <reminder>
dopy add "Pay the telephone bill" personal new --reminder=today
with default values for tag, status and reminder
dopy add "Implement new features on my project"
- List taks
List all open tasks
dopy ls
$ python do.py ls
$ dopy ls
+--+-----------------------------+--------+------+--------+-------------------+
|ID| Name| Tag|Status|Reminder| Created|
+--+-----------------------------+--------+------+--------+-------------------+
| 3| Pay telephone bill|personal| new| today|2012-12-31 08:03:15|
| 4|Implement features on project| default| new| None|2012-12-31 08:03:41|
+--+-----------------------------+--------+------+--------+-------------------+
TOTAL:2 tasks
By tag
`dopy ls --tag=personal
By name
dopy ls --search=phone
By status
dopy ls --status=done
All
dopy ls --all
- Mark as done
dopy done <id>
dopy done 2
- Remove a task
dopy rm 2
- Get a task in shell mode for editing
dopy get 3
$ dopy get 3
To show the task
>>> print task
To show a field (available name, tag, status, reminder)
>>> task.name
To edit the task assign to a field
>>> task.name = "Other name"
To delete a task
>>> task.delete()
To exit
>>> quit()
######################################
>>> print task
<Row {'status': 'new', 'name': 'Pay telephone bill', 'deleted': False, 'created_on': datetime.datetime(2012, 12, 31, 8, 3, 15), 'tag': 'personal', 'reminder': 'today', 'id': 3}>
>>> task.status
'new'
>>> task.status = "working"
>>> task.status
'working'
>>>
NOTES
Doing a dopy ls you can see the ID of the tasks, using this ID you can assign notes
- Including a note
dopy note 1 "This is the note for the task 1"
The above command inserts the note and prints the TASK with notes.
+--+-----+-------+------+--------+-----------+
|ID| Name| Tag|Status|Reminder| Created|
+--+-----+-------+------+--------+-----------+
| 1|teste|default| new| None|01/01-02:14|
+--+-----+-------+------+--------+-----------+
NOTES:
+------------------------------------+
0 This is the note fot task 1
+------------------------------------+
1 notes
- Consulting the notes
You can also show all notes for a task using the show command
dopy show 1
+--+-----+-------+------+--------+-----------+
|ID| Name| Tag|Status|Reminder| Created|
+--+-----+-------+------+--------+-----------+
| 1|teste|default| new| None|01/01-02:14|
+--+-----+-------+------+--------+-----------+
NOTES:
+----------------------------------------+
0 This is the note fot task 1
1 This is another note for task 1
+----------------------------------------+
2 notes
- Removing a note
Notes can be removed by its index number.
Example: To remove the latest note
dopy note 1 --rm=-1
where -1 is the index for the last element in notes
To remove the first note
dopy note 1 --rm=0
Switching DBS
It is possible to use more than one database by switching using --use argument
dopy add "Including on another db" --use=mynewdb
The above command will use a db called "mynewdb" (it will be created if not exists)
In the same way you have to specify the db for other operations
dopy ls --all --use=mynewdb to list all tasks on the db
Note, you can also change the default db in .dopyrc file
TODO
- Sync with google task
- Sync with remember the milk
- Generate HTML and PDF reports on /tmp
Expand
Collapse
(237 lines)
https://snipt.net/embed/8eb658a4cf3660d38d8bc80a7c5f8d3b/
https://snipt.net/raw/8eb658a4cf3660d38d8bc80a7c5f8d3b/
8eb658a4cf3660d38d8bc80a7c5f8d3b
markdown
Markdown
237
2013-05-20T12:38:24
True
True
Dec 31, 2012 at 10:59 AM
/api/public/snipt/52591/
dopy-cli-tool-to-manage-your-to-do-list-based-on-docopt-and-dal
<p><a href="https://github.com/rochacbruno/dopy">https://github.com/rochacbruno/dopy</a></p>
<h1>dopy</h1>
<pre><code> ____ _
| _ \ ___ _ __ _ _| |
| | | |/ _ \ | '_ \| | | | |
| |_| | (_) || |_) | |_| |_|
|____/ \___(_) .__/ \__, (_)
|_| |___/
</code></pre>
<p>To Do list on Command Line Interface</p>
<p>Manage to-do list on a shell based simple interface and stores your to-do locally on a sqlite database</p>
<p>optionally use your Dropbox to store the database</p>
<p><img src="https://raw.github.com/rochacbruno/dopy/master/dopy.png" alt="image" /></p>
<h1>Instalation</h1>
<p><code>pip install dopy</code></p>
<p>or</p>
<p><code>git clone https://github.com/rochacbruno/dopy</code></p>
<p><code>cd dopy</code></p>
<p><code>python setup.py install</code></p>
<p>or</p>
<p><code>git clone https://github.com/rochacbruno/dopy</code></p>
<p><code>chmod +x dopy/dopy/do.py</code></p>
<p><code>sudo ln -s path/to/dopy/dopy/do.py /bin/dopy</code></p>
<p><strong>Maybe the pip option will not be working for a while</strong></p>
<h1>Usage</h1>
<pre><code>____ _
| _ \ ___ _ __ _ _| |
| | | |/ _ \ | '_ \| | | | |
| |_| | (_) || |_) | |_| |_|
|____/ \___(_) .__/ \__, (_)
|_| |___/
Usage:
do.py [--use=<db>] [--args]
do.py add <name> [<tag>] [<status>] [--reminder=<reminder>] [--use=<db>] [--args]
do.py done <id> [--use=<db>] [--args]
do.py ls [--all] [--tag=<tag>] [--status=<status>] [--search=<term>] [--date=<date>] [--month=<month>] [--day=<day>] [--year=<year>] [--use=<db>] [--args]
do.py rm <id> [--use=<db>] [--args]
do.py get <id> [--use=<db>] [--args]
do.py note <id> [--use=<db>] [--rm=<noteindex>] [--args]
do.py show <id> [--use=<db>] [--args]
do.py note <id> <note> [--use=<db>] [--args]
do.py export <path> [--format=<format>] [--use=<db>] [--args]
do.py setpath <path> [--args]
do.py use <db> [--args]
do.py -h | --help [--args]
do.py --version [--args]
do.py --args
Options:
-h --help Show this screen.
--version Show version.
--args Show args.
</code></pre>
<ol>
<li><p>to enter in SHELL mode
<code>python do.py</code> or simply <code>dopy</code> if installed</p></li>
<li><p>Add a new task
dopy <name> <tag> <status> <reminder></p></li>
</ol>
<p><code>dopy add "Pay the telephone bill" personal new --reminder=today</code></p>
<p>with default values for tag, status and reminder</p>
<p><code>dopy add "Implement new features on my project"</code></p>
<ol>
<li>List taks</li>
</ol>
<p>List all open tasks</p>
<p><code>dopy ls</code></p>
<pre><code>$ python do.py ls
$ dopy ls
+--+-----------------------------+--------+------+--------+-------------------+
|ID| Name| Tag|Status|Reminder| Created|
+--+-----------------------------+--------+------+--------+-------------------+
| 3| Pay telephone bill|personal| new| today|2012-12-31 08:03:15|
| 4|Implement features on project| default| new| None|2012-12-31 08:03:41|
+--+-----------------------------+--------+------+--------+-------------------+
TOTAL:2 tasks
</code></pre>
<p>By tag</p>
<p>`<code>dopy ls --tag=personal</code></p>
<p>By name</p>
<p><code>dopy ls --search=phone</code></p>
<p>By status</p>
<p><code>dopy ls --status=done</code></p>
<p>All</p>
<p><code>dopy ls --all</code></p>
<ol>
<li>Mark as done</li>
</ol>
<p>dopy done <id></p>
<p><code>dopy done 2</code></p>
<ol>
<li>Remove a task</li>
</ol>
<p><code>dopy rm 2</code></p>
<ol>
<li>Get a task in shell mode for editing</li>
</ol>
<p><code>dopy get 3</code></p>
<pre><code>$ dopy get 3
To show the task
>>> print task
To show a field (available name, tag, status, reminder)
>>> task.name
To edit the task assign to a field
>>> task.name = "Other name"
To delete a task
>>> task.delete()
To exit
>>> quit()
######################################
>>> print task
<Row {'status': 'new', 'name': 'Pay telephone bill', 'deleted': False, 'created_on': datetime.datetime(2012, 12, 31, 8, 3, 15), 'tag': 'personal', 'reminder': 'today', 'id': 3}>
>>> task.status
'new'
>>> task.status = "working"
>>> task.status
'working'
>>>
</code></pre>
<h1>NOTES</h1>
<p>Doing a <code>dopy ls</code> you can see the <code>ID</code> of the tasks, using this <code>ID</code> you can assign notes</p>
<ol>
<li>Including a note</li>
</ol>
<p><code>dopy note 1 "This is the note for the task 1"</code></p>
<p>The above command inserts the note and prints the TASK with notes.</p>
<pre><code>+--+-----+-------+------+--------+-----------+
|ID| Name| Tag|Status|Reminder| Created|
+--+-----+-------+------+--------+-----------+
| 1|teste|default| new| None|01/01-02:14|
+--+-----+-------+------+--------+-----------+
NOTES:
+------------------------------------+
0 This is the note fot task 1
+------------------------------------+
1 notes
</code></pre>
<ol>
<li>Consulting the notes</li>
</ol>
<p>You can also show all notes for a task using the show command</p>
<p><code>dopy show 1</code></p>
<pre><code>+--+-----+-------+------+--------+-----------+
|ID| Name| Tag|Status|Reminder| Created|
+--+-----+-------+------+--------+-----------+
| 1|teste|default| new| None|01/01-02:14|
+--+-----+-------+------+--------+-----------+
NOTES:
+----------------------------------------+
0 This is the note fot task 1
1 This is another note for task 1
+----------------------------------------+
2 notes
</code></pre>
<ol>
<li>Removing a note</li>
</ol>
<p>Notes can be removed by its index number.</p>
<p>Example: To remove the latest note</p>
<p><code>dopy note 1 --rm=-1</code></p>
<p>where <code>-1</code> is the index for the last element in notes</p>
<p>To remove the first note</p>
<p><code>dopy note 1 --rm=0</code></p>
<h1>Switching DBS</h1>
<p>It is possible to use more than one database by switching using <code>--use</code> argument</p>
<p><code>dopy add "Including on another db" --use=mynewdb</code></p>
<p>The above command will use a db called "mynewdb" (it will be created if not exists)</p>
<p>In the same way you have to specify the db for other operations</p>
<p><code>dopy ls --all --use=mynewdb</code> to list all tasks on the db</p>
<blockquote>
<p>Note, you can also change the default db in .dopyrc file</p>
</blockquote>
<h1>TODO</h1>
<ul>
<li>Sync with google task</li>
<li>Sync with remember the milk</li>
<li>Generate HTML and PDF reports on /tmp</li>
</ul>
cli, pyplanet, python, web2py
#52562
RQ (Redis Queue)
RQ (Redis Queue) is a simple Python library for queueing jobs and processing them in the background with workers. It is backed by Redis and it is designed to have a low barrier to entry. It should be integrated in your web(2py) stack easily.
http://python-rq.org
web2py
Free open source full-stack framework for rapid development of fast, scalable, secure and portable database-driven web-based applications. Written and programmable in Python.
http://www.web2py.com
Queueing jobs with RQ and web2py
web2py as many other web frameworks works in a request -> response environment, which means that there is a lifetime for things to be done. This lifetime we call "request time", it is the time between the client requests a resource (i.e hits an url of our app or post a form) and the time that the server gives the response back to the client (i.e: The server sends html, json or any other kind of response).
The problem with this is the fact that we have a time-out and the user does not want to wait for tasks to be done, I mean in example for creating image thumbnails, users have to upload a picture and then wait for the thumbnail to be created to have a response from server. Or in the case of sending an email, user fill a contact form and have to wait for the message to be sent. It can take a long time and sometimes it will fail.
The solution is to enqueue that jobs on background and then watch its results to give a response to the user, this response can be given through a websocket or ajax long pooling. (I will not cover this here)
Setting up
- install Redis
- In debian based linuxes you can do:
sudo apt-get install redis-server
- Install RQ (redis queue)
case 1 : Sending email in background
User will fill our contact form and then click in submit, instead of sending the email we are going to enqueue the email to be sent by the redis queue.
1. In your models create your Queue object (also you need to have the mail settings)
models/db.py
from gluon.tools import Mail
mail = Mail()
mail.settings.server = "smtp.google.com:587"
mail.settings.sender = "you@gmail.com"
mail.settings.login = "you:yourpassword"
models/queue.py
from redis import Redis
from rq import Queue
q = Queue(connection=Redis())
The above will use the default Redis connection port to localhost, take a look at RQ docs if you need to set another redis server.
2. In your controller create the contact action which returns a form.
controllers/default.py
def contact():
form = SQLFORM.factory(Field("name"), Field("message"))
if form.accepts(request):
# enqueue the email to be sent!
q.enqueue(mail.send,
to="you@gmail.com",
subject="%(name)s contacted you" % form.vars,
message=form.vars.message)
# do whatever you want
response.flash = "email successfully sent!"
case 2 : Creating an image thumbnail
User will upload a picture and you are going to create a THUMBNAIL and store the thumbnail in /static/thumbs folder
1. Define some models
models/db.py
Picture = db.define_table("pictures",
Field("name"),
Field("picture", "upload")
)
models/queue.py
from redis import Redis
from rq import Queue
q = Queue(connection=Redis())
2. Create the form
controllers/default.py
# requires PIL to be installed
# sudo apt-get install python-imaging
from gluon.contrib.imageutils import THUMB
def add_picture():
form = SQLFORM(Picture, submit_button="send")
if form.process().accepted:
#enqueue thumbnail to be created
q.enqueue(THUMB, form.vars.picture)
Put the workers to work
On the cases above we just enqueued tasks to be executed by the workers, now we need the worker running.
web2py environment
The worker should run under the web2py environment, because we are using web2py modules to send emails and create the thumbnail, so the RQ worker should be started with this script.
1. Create the web2py RQ worker
/some/path/web2py-rq.py
import sys
from rq import Queue, Connection, Worker
# Provide queue names to listen to as arguments to this script,
# similar to rqworker
with Connection():
qs = map(Queue, sys.argv[1:]) or [Queue()]
w = Worker(qs)
w.work()
Start the above worker under web2py environment
cd /path/to/web2py
python web2py.py -S yourappname -M -R /some/path/web2py-rq.py
With the above worker running the enqueued tasks will be executed and then worker will keep listening for new tasks.
You can also put the worker to run in backgroungm for this you shoud use nohup python web2py.py -S yourappname -M -R /some/path/web2py-rq.py & or even better you can put this to run under the supervidord
with the worker running you should see this console:
python web2py/web2py.py -S app -M -R /projects/web2py-rq.py
web2py Web Framework
Created by Massimo Di Pierro, Copyright 2007-2012
Version 2.4.1-alpha.2+timestamp.2012.12.28.16.18.51
Database drivers available: SQLite(sqlite3), MySQL(pymysql), PostgreSQL(pg8000), IMAP(imaplib)
[2012-12-31 00:33] DEBUG: worker: Registering birth of worker precise64.15755
[2012-12-31 00:33] INFO: worker: RQ worker started, version 0.3.2
[2012-12-31 00:33] INFO: worker:
[2012-12-31 00:33] INFO: worker: *** Listening on default...
[2012-12-31 00:34] INFO: worker: default: send(to='someone@gmail.com', message='blah', subject='testing') (a069b2c6-f908-4806-8534-b00c43996cf4)
Monitoring
RQ has some nice ways for monitoring the jobs by command-line or by its dashboard.
command line:
To see what queues exist and what workers are active, just type rqinfo:
$ rqinfo
high |██████████████████████████ 20
low |██████████████ 12
default |█████████ 8
3 queues, 45 jobs total
Bricktop.19233 idle: low
Bricktop.19232 idle: high, default, low
Bricktop.18349 idle: default
3 workers, 3 queues
As you can see it is possible to start many workers.
Dashboard
The easiest way is probably to use the RQ dashboard, a separately distributed tool, which is a lightweight webbased monitor frontend for RQ, which looks like this:
RQ dashboard https://github.com/nvie/rq-dashboard

https://snipt.net/embed/7204ab2b27804acb5bb59c68b153b7bb/
https://snipt.net/raw/7204ab2b27804acb5bb59c68b153b7bb/
7204ab2b27804acb5bb59c68b153b7bb
markdown
Markdown
177
2013-05-21T01:41:41
True
True
Dec 30, 2012 at 09:05 PM
/api/public/snipt/52562/
web2py-and-redis-queue
<h2>RQ (Redis Queue)</h2>
<p>RQ (Redis Queue) is a simple Python library for queueing jobs and processing them in the background with workers. It is backed by Redis and it is designed to have a low barrier to entry. It should be integrated in your web(2py) stack easily.</p>
<p><a href="http://python-rq.org">http://python-rq.org</a></p>
<h2>web2py</h2>
<p>Free open source full-stack framework for rapid development of fast, scalable, secure and portable database-driven web-based applications. Written and programmable in Python.</p>
<p><a href="http://www.web2py.com">http://www.web2py.com</a></p>
<h1>Queueing jobs with RQ and web2py</h1>
<p>web2py as many other web frameworks works in a request -> response environment, which means that there is a lifetime for things to be done. This lifetime we call "request time", it is the time between the client <strong>request</strong>s a resource (i.e hits an url of our app or post a form) and the time that the server gives the <strong>response</strong> back to the client (i.e: The server sends html, json or any other kind of response).</p>
<p>The problem with this is the fact that we have a time-out and the user does not want to wait for tasks to be done, I mean in example for creating image thumbnails, users have to upload a picture and then wait for the thumbnail to be created to have a response from server. Or in the case of sending an email, user fill a contact form and have to wait for the message to be sent. It can take a long time and sometimes it will fail.</p>
<p>The solution is to enqueue that jobs on background and then watch its results to give a response to the user, this response can be given through a websocket or ajax long pooling. (I will not cover this here) </p>
<h2>Setting up</h2>
<ul>
<li>install Redis
<ul>
<li>In debian based linuxes you can do: <code>sudo apt-get install redis-server</code></li>
</ul></li>
<li>Install RQ (redis queue)
<ul>
<li><code>sudo pip install rq</code></li>
</ul></li>
</ul>
<h2>case 1 : Sending email in background</h2>
<p>User will fill our contact form and then click in submit, instead of sending the email we are going to enqueue the email to be sent by the redis queue.</p>
<h4>1. In your models create your Queue object (also you need to have the mail settings)</h4>
<p><code>models/db.py</code></p>
<pre><code>from gluon.tools import Mail
mail = Mail()
mail.settings.server = "smtp.google.com:587"
mail.settings.sender = "you@gmail.com"
mail.settings.login = "you:yourpassword"
</code></pre>
<p><code>models/queue.py</code></p>
<pre><code>from redis import Redis
from rq import Queue
q = Queue(connection=Redis())
</code></pre>
<p>The above will use the default Redis connection port to localhost, take a look at RQ docs if you need to set another redis server.</p>
<h4>2. In your controller create the contact action which returns a form.</h4>
<p><code>controllers/default.py</code></p>
<pre><code>def contact():
form = SQLFORM.factory(Field("name"), Field("message"))
if form.accepts(request):
# enqueue the email to be sent!
q.enqueue(mail.send,
to="you@gmail.com",
subject="%(name)s contacted you" % form.vars,
message=form.vars.message)
# do whatever you want
response.flash = "email successfully sent!"
</code></pre>
<h2>case 2 : Creating an image thumbnail</h2>
<p>User will upload a picture and you are going to create a THUMBNAIL and store the thumbnail in /static/thumbs folder</p>
<h4>1. Define some models</h4>
<p><code>models/db.py</code></p>
<pre><code>Picture = db.define_table("pictures",
Field("name"),
Field("picture", "upload")
)
</code></pre>
<p><code>models/queue.py</code></p>
<pre><code>from redis import Redis
from rq import Queue
q = Queue(connection=Redis())
</code></pre>
<h4>2. Create the form</h4>
<p><code>controllers/default.py</code></p>
<pre><code># requires PIL to be installed
# sudo apt-get install python-imaging
from gluon.contrib.imageutils import THUMB
def add_picture():
form = SQLFORM(Picture, submit_button="send")
if form.process().accepted:
#enqueue thumbnail to be created
q.enqueue(THUMB, form.vars.picture)
</code></pre>
<h1>Put the workers to work</h1>
<p>On the cases above we just enqueued tasks to be executed by the workers, now we need the worker running.</p>
<h2>web2py environment</h2>
<p>The worker should run under the web2py environment, because we are using web2py modules to send emails and create the thumbnail, so the RQ worker should be started with this script.</p>
<h3>1. Create the web2py RQ worker</h3>
<p><code>/some/path/web2py-rq.py</code></p>
<pre><code>import sys
from rq import Queue, Connection, Worker
# Provide queue names to listen to as arguments to this script,
# similar to rqworker
with Connection():
qs = map(Queue, sys.argv[1:]) or [Queue()]
w = Worker(qs)
w.work()
</code></pre>
<h3>Start the above worker under web2py environment</h3>
<pre><code>cd /path/to/web2py
python web2py.py -S yourappname -M -R /some/path/web2py-rq.py
</code></pre>
<p>With the above worker running the enqueued tasks will be executed and then worker will keep listening for new tasks.</p>
<p>You can also put the worker to run in backgroungm for this you shoud use <code>nohup python web2py.py -S yourappname -M -R /some/path/web2py-rq.py &</code> or even better you can put this to run under the <strong>supervidord</strong></p>
<h4>with the worker running you should see this console:</h4>
<pre><code>python web2py/web2py.py -S app -M -R /projects/web2py-rq.py
web2py Web Framework
Created by Massimo Di Pierro, Copyright 2007-2012
Version 2.4.1-alpha.2+timestamp.2012.12.28.16.18.51
Database drivers available: SQLite(sqlite3), MySQL(pymysql), PostgreSQL(pg8000), IMAP(imaplib)
[2012-12-31 00:33] DEBUG: worker: Registering birth of worker precise64.15755
[2012-12-31 00:33] INFO: worker: RQ worker started, version 0.3.2
[2012-12-31 00:33] INFO: worker:
[2012-12-31 00:33] INFO: worker: *** Listening on default...
[2012-12-31 00:34] INFO: worker: default: send(to='someone@gmail.com', message='blah', subject='testing') (a069b2c6-f908-4806-8534-b00c43996cf4)
</code></pre>
<h1>Monitoring</h1>
<p>RQ has some nice ways for monitoring the jobs by command-line or by its dashboard.</p>
<h2>command line:</h2>
<p>To see what queues exist and what workers are active, just type rqinfo:</p>
<pre><code>$ rqinfo
high |██████████████████████████ 20
low |██████████████ 12
default |█████████ 8
3 queues, 45 jobs total
Bricktop.19233 idle: low
Bricktop.19232 idle: high, default, low
Bricktop.18349 idle: default
3 workers, 3 queues
</code></pre>
<p>As you can see it is possible to start many workers.</p>
<h2>Dashboard</h2>
<p>The easiest way is probably to use the RQ dashboard, a separately distributed tool, which is a lightweight webbased monitor frontend for RQ, which looks like this:</p>
<p>RQ dashboard <a href="https://github.com/nvie/rq-dashboard">https://github.com/nvie/rq-dashboard</a></p>
<p><img src="http://python-rq.org/img/dashboard.png" alt="dash" /></p>
pyplanet, python, redis, snipt-expand, web2py
#51247
microblog app
Este tutorial foi criado para o evento RuPy Brasil em parceria com a ZNC Sistemas.
O download do app pode ser feito em: Download pacote w2p
O tutorial em PDF: Tutorial em PDF
Tutorial: Criando um microblog app
Agora pretendo aproveitar que o blog tem mais espaço que o PDF para detalhar um pouco mais o app de microblog e também implementar algumas funcionalidades extra.
CONTINUE:
Expand
Collapse
(13 lines)
https://snipt.net/embed/128c5645212cc0a70c0656b0c8c49233/
https://snipt.net/raw/128c5645212cc0a70c0656b0c8c49233/
128c5645212cc0a70c0656b0c8c49233
markdown
Markdown
13
2013-05-20T04:24:36
True
True
Dec 04, 2012 at 10:48 PM
/api/public/snipt/51247/
microblog-app
<h1>microblog app</h1>
<p>Este tutorial foi criado para o evento RuPy Brasil em parceria com a ZNC Sistemas.</p>
<p>O download do app pode ser feito em: <a href="http://dl.dropbox.com/u/830444/web2py.app.microblog.w2p">Download pacote w2p</a></p>
<p>O tutorial em PDF: <a href="http://dl.dropbox.com/u/830444/web2py_tutorial.pdf">Tutorial em PDF</a></p>
<h1>Tutorial: Criando um microblog app</h1>
<p>Agora pretendo aproveitar que o blog tem mais espaço que o PDF para detalhar um pouco mais o app de microblog e também implementar algumas funcionalidades extra.</p>
<p>CONTINUE:</p>
python, web2py
#47340
Quick and dirty search form example
Considering models/db.py
status_options = {"0": "pending", "1": "confirmed", "3": "canceled"}
db.define_table("orders",
Field("id_buyer", "reference auth_user"),
Field("order_date", "date"),
Field("status",
requires=IS_IN_SET(status_options),
represent= lambda value, row: status_options[value]
),
Field("obs","text")
)
And the search function controllers/default.py
import datetime
@auth.requires_login()
def index():
# default values to keep the form when submitted
# if you do not want defaults set all below to None
status_default = request.vars.status
date_initial_default = \
datetime.datetime.strptime(request.vars.date_initial, "%Y-%m-%d") \
if request.vars.date_inicial else None
date_final_default = \
datetime.datetime.strptime(request.vars.date_final, "%Y-%m-%d") \
if request.vars.date_final else None
obs_default = request.vars.obs
# The search form created with .factory
form = SQLFORM.factory(
Field("status",
default=status_default
requires=IS_EMPTY_OR(
IS_IN_SET(status_options, zero="-- All --")
),
),
Field("date_initial", "date", default=date_initial_default),
Field("date_final", "date", default=date_final_default),
Field("obs", default=obs_default),
formstyle='divs',
submit_button="Search",
)
# The base query to fetch all orders of the current logged user
query = db.orders.id_buyer == auth.user_id
# testing if the form was accepted
if form.process().accepted:
# gathering form submitted values
status = form.vars.status
date_initial = form.vars.date_initial
date_final = form.vars.date_final
obs = form.vars.obs
# more dynamic conditions in to query
if status:
query &= db.orders.status == status
if date_initial:
query &= db.orders.order_date >= date_initial
if date_final:
query &= db.orders.order_date <= date_final
if obs:
# A simple text search with %like%
query &= db.orders.obs.like("%%%s%%" % obs)
count = db(query).count()
results = db(query).select(orderby=~db.orders.data)
msg = T("%s registers" % count )
return dict(form=form, msg=msg, results=results)
Optionally you can create a view file in views/default/index.html
{{extend 'layout.html'}}
{{=form}}
<hr />
{{=msg}}
{{=results}}
the end result

Download the app: http://dl.dropbox.com/u/830444/web2py.app.busca.w2p
If you need a better and complex search engine I recommend Whoosh.
Expand
Collapse
(98 lines)
https://snipt.net/embed/8e99ce76372ef7414866c0c424b386b6/
https://snipt.net/raw/8e99ce76372ef7414866c0c424b386b6/
8e99ce76372ef7414866c0c424b386b6
markdown
Markdown
98
2013-05-20T16:46:50
True
True
Sep 18, 2012 at 08:13 PM
/api/public/snipt/47340/
search-form-with-web2py
<h1>Quick and dirty search form example</h1>
<p>Considering <code>models/db.py</code></p>
<pre><code>status_options = {"0": "pending", "1": "confirmed", "3": "canceled"}
db.define_table("orders",
Field("id_buyer", "reference auth_user"),
Field("order_date", "date"),
Field("status",
requires=IS_IN_SET(status_options),
represent= lambda value, row: status_options[value]
),
Field("obs","text")
)
</code></pre>
<p>And the search function <code>controllers/default.py</code> </p>
<pre><code>import datetime
@auth.requires_login()
def index():
# default values to keep the form when submitted
# if you do not want defaults set all below to None
status_default = request.vars.status
date_initial_default = \
datetime.datetime.strptime(request.vars.date_initial, "%Y-%m-%d") \
if request.vars.date_inicial else None
date_final_default = \
datetime.datetime.strptime(request.vars.date_final, "%Y-%m-%d") \
if request.vars.date_final else None
obs_default = request.vars.obs
# The search form created with .factory
form = SQLFORM.factory(
Field("status",
default=status_default
requires=IS_EMPTY_OR(
IS_IN_SET(status_options, zero="-- All --")
),
),
Field("date_initial", "date", default=date_initial_default),
Field("date_final", "date", default=date_final_default),
Field("obs", default=obs_default),
formstyle='divs',
submit_button="Search",
)
# The base query to fetch all orders of the current logged user
query = db.orders.id_buyer == auth.user_id
# testing if the form was accepted
if form.process().accepted:
# gathering form submitted values
status = form.vars.status
date_initial = form.vars.date_initial
date_final = form.vars.date_final
obs = form.vars.obs
# more dynamic conditions in to query
if status:
query &= db.orders.status == status
if date_initial:
query &= db.orders.order_date >= date_initial
if date_final:
query &= db.orders.order_date <= date_final
if obs:
# A simple text search with %like%
query &= db.orders.obs.like("%%%s%%" % obs)
count = db(query).count()
results = db(query).select(orderby=~db.orders.data)
msg = T("%s registers" % count )
return dict(form=form, msg=msg, results=results)
</code></pre>
<p>Optionally you can create a view file in <code>views/default/index.html</code></p>
<pre><code>{{extend 'layout.html'}}
{{=form}}
<hr />
{{=msg}}
{{=results}}
</code></pre>
<h1>the end result</h1>
<p><img src="http://i.imgur.com/c6X9s.png" alt="" /></p>
<p>Download the app: http://dl.dropbox.com/u/830444/web2py.app.busca.w2p </p>
<blockquote>
<p>If you need a better and complex search engine I recommend Whoosh.</p>
</blockquote>
python, web2py