Slide 1

Slide 1 text

@pydanny [email protected] Keynote DjangoCircus 2013

Slide 2

Slide 2 text

@pydanny [email protected] Daniel Greenfeld Hi everyone. My name is Daniel Greenfeld. I’m the guy with the unenviable task of being the keynote after Brandon Rhodes.

Slide 3

Slide 3 text

@pydanny [email protected] @pydanny This is me.

Slide 4

Slide 4 text

@pydanny [email protected] I work as a principal for Cartwheel Web, doing Python and Django. The company is named after cartwheels.

Slide 5

Slide 5 text

@pydanny [email protected] http://2scoops.org Danny: 128,546++ Audrey: 121,871++ Co-wrote a book. There is Audrey. She half of the book.

Slide 6

Slide 6 text

@pydanny [email protected] Django conferences have a tradition. Django has a tradition.

Slide 7

Slide 7 text

@pydanny [email protected] e Django Tradition of Invited Critical Talks This is where some luminary is invited to give a talk that takes Django to task in some way.

Slide 8

Slide 8 text

@pydanny [email protected] is Isn’t A Hate Django Talk. I’m not giving one of those talks. Why not?

Slide 9

Slide 9 text

@pydanny [email protected] Why Not?

Slide 10

Slide 10 text

@pydanny [email protected] Negative It’s Too Easy to be

Slide 11

Slide 11 text

@pydanny [email protected] Example: “Class Based Views Suck” Saying this is easy. I used to say it all the time. Twitter, IRC, forums

Slide 12

Slide 12 text

@pydanny [email protected] You Know What’s Hard?

Slide 13

Slide 13 text

@pydanny [email protected] Working Stuff Delivering

Slide 14

Slide 14 text

@pydanny [email protected] Rants are fun but...

Slide 15

Slide 15 text

@pydanny [email protected] No one would remember Zed Shaw if he hadn’t written Learn Python the Hard Way* *Just one of many of his efforts.

Slide 16

Slide 16 text

@pydanny [email protected] Contribute Get Your Hands Dirty and

Slide 17

Slide 17 text

@pydanny [email protected] Running Events Writing Books Pull Requests Jannis used to say this all the time to me. This event is awesome. Learn Python the Hard Way. Two Scoops of Django

Slide 18

Slide 18 text

@pydanny [email protected] is Isn’t A Hate Django Talk. So no, this isn’t a rant about Django. Instead...

Slide 19

Slide 19 text

@pydanny [email protected] Django is Awesome ...it’s a celebration about what makes Django awesome. Which was the result of a lot of people delivering working stuff. Their hard work has made so much possible.

Slide 20

Slide 20 text

@pydanny [email protected] Why is Django Awesome?

Slide 21

Slide 21 text

@pydanny [email protected] Reason #1 Django is Everywhere

Slide 22

Slide 22 text

@pydanny [email protected] Django Everywhere NASA Disqus Google Grove.io HP IBM Instagram Mozilla Sony Cashstar BitBucket Canonical PBS National Geographic Microsoft Humble Bundle Django Circus djangocon.com PBS Pinterest Rdio e Onion Library of Congress Causes Politifact OpenStack Rackspace Discovery Channel Newspapers Lexis Nexis 2scoops.org Lanyrd Gondor

Slide 23

Slide 23 text

@pydanny [email protected] Django Everywhere NASA Disqus Google Grove.io HP IBM Instagram Mozilla Sony Cashstar BitBucket Canonical PBS National Geographic Microsoft Humble Bundle Django Circus djangocon.com PBS Pinterest Rdio e Onion Library of Congress Causes Politifact OpenStack Rackspace Discovery Channel Newspapers Lexis Nexis 2scoops.org Lanyrd Gondor Django is used on many projects. NASA’s Nebula begat OpenStack. I started with Django while at NASA. One of NASA’s products is Nebula, the god-parent of OpenStack.

Slide 24

Slide 24 text

@pydanny [email protected] Reason #2 Django is Powered by Python

Slide 25

Slide 25 text

@pydanny [email protected] Python is Awesome

Slide 26

Slide 26 text

@pydanny [email protected] Python has a Style Guide PEP-0008

Slide 27

Slide 27 text

@pydanny [email protected] Python has Zen PEP-0020

Slide 28

Slide 28 text

@pydanny [email protected] Most importantly...

Slide 29

Slide 29 text

@pydanny [email protected] Python shares the same rst two letters as me. Python Pydanny

Slide 30

Slide 30 text

@pydanny [email protected] Reason #3 Django has Awesome APIs

Slide 31

Slide 31 text

@pydanny [email protected] API win: Understandable No funky names besides ‘django’ models views templates forms settings admin messages caching logging sessions No funky names except for Django, which means we don’t have to spend much time memorizing colorful names for common objects.

Slide 32

Slide 32 text

@pydanny [email protected] Case Study: python-requests vs. django.test.client

Slide 33

Slide 33 text

@pydanny [email protected] python-requests vs. django.test.client >>> r = requests.get('http://127.0.0.1:8000') >>> r.status_code 200 >>> params = {'key1': 'value1', 'key2': 'value2'} >>> r = requests.get("http://127.0.0.1:8000", params) >>> r.status_code 200 >>> import requests >>> from django.test.client import Client >>> requests = Client() Can anyone recognize this code? It’s requests in action, right? Nope, it’s the django test client! Anyway, I think it’s says something when two popular toolsets have similar API designs.

Slide 34

Slide 34 text

@pydanny [email protected] API Win Conventions

Slide 35

Slide 35 text

@pydanny [email protected] forms.py models.py views.py templates/ Forms Models Views Templates

Slide 36

Slide 36 text

@pydanny [email protected] forms.py from  django  import  forms from  pies.models  import  Pie     class  PieForm(forms.ModelForm):          class  Meta:                model  =  Pie                fields  =  ('filling',  ) No code names. No puns. No underscores. Intuitive.

Slide 37

Slide 37 text

@pydanny [email protected] from  django.db  import  models     class  Pie(models.Model):          STATUS_UNBAKED,  STATUS_BAKED  =  0,  1        FILLING_APPLE,  FILLING_MEAT  =  0,  1        STATUS_CHOICES  =  (                (STATUS_UNBAKED,  "Unbaked"),                (STATUS_BAKED,  "Baked")        )        FILLING_CHOICES  =  (                (FILLING_APPLE,  "Apple"),                (FILLING_MEAT,  "Meat"),        )          status  =  models.IntegerField(choices=STATUS_CHOICES,                                                  default=STATUS_UNBAKED)        filling  =  models.IntegerField(choices=FILLING_CHOICES)          def  __unicode__(self):                return  "{status}  {filling}  pie".format(                        status=self.get_status_display(),                        filling=self.get_filling_display()                ) models.py The Pie inherits right from Models. How awesome is that? What about model field definitions? Obvious!

Slide 38

Slide 38 text

@pydanny [email protected] Pro-Tip

Slide 39

Slide 39 text

@pydanny [email protected] pro-tip While Fat Models are Great Fat models are when you move as much logic as possible from views to models, so that you can more readily re-use the same code in more than one view. Very commonly between HTML and JSON versions of views.

Slide 40

Slide 40 text

@pydanny [email protected] pro-tip Overly Large Models Are Not

Slide 41

Slide 41 text

@pydanny [email protected] Really. class  Package(BaseModel):        title  =  models.CharField(_("Title"),  max_length="100")        slug  =  models.SlugField(_("Slug"),  help_text="Enter  a  valid  'slug'  consisting  of  letters,  numbers,  underscores  or   hyphens.
Values  will  be  converted  to  lowercase.",  unique=True)        category  =  models.ForeignKey(Category,  verbose_name="Installation")        repo_description  =  models.TextField(_("Repo  Description"),  blank=True)        repo_url  =  models.URLField(_("repo  URL"),  help_text=repo_url_help_text,  blank=True,  unique=True,  verify_exists=True)        repo_watchers  =  models.IntegerField(_("repo  watchers"),  default=0)        repo_forks  =  models.IntegerField(_("repo  forks"),  default=0)        repo_commits  =  models.IntegerField(_("repo  commits"),  default=0)        pypi_url  =  models.URLField(_("PyPI  slug"),  help_text=pypi_url_help_text,  blank=True,  default='',  verify_exists=True)        pypi_downloads  =  models.IntegerField(_("Pypi  downloads"),  default=0)        participants  =  models.TextField(_("Participants"),                                                help_text="List  of  collaborats/participants  on  the  project",  blank=True)        usage  =  models.ManyToManyField(User,  blank=True)        created_by  =  models.ForeignKey(User,  blank=True,  null=True,  related_name="creator",  on_delete=models.SET_NULL)        last_modified_by  =  models.ForeignKey(User,  blank=True,  null=True,  related_name="modifier",  on_delete=models.SET_NULL)        @property        def  pypi_version(self):                string_ver_list  =  self.version_set.values_list('number',  flat=True)                if  string_ver_list:                        vers_list  =  [versioner(v)  for  v  in  string_ver_list]                        latest  =  sorted(vers_list)[-­1]                        return  str(latest)                return  ''        @property        def  pypi_name(self):                """  return  the  pypi  name  of  a  package"""                if  not  self.pypi_url.strip():                        return  ""                name  =  self.pypi_url.replace("http://pypi.python.org/pypi/",  "")                if  "/"  in  name:                        return  name[:name.index("/")]                return  name        @property        def  last_updated(self):                try:                        last_commit  =  self.commit_set.latest('commit_date')                        if  last_commit:                                return  last_commit.commit_date                except  ObjectDoesNotExist:                        pass                return  None        @property        def  repo(self):                return  get_repo_for_repo_url(self.repo_url)        @property        def  active_examples(self):                return  self.packageexample_set.filter(active=True)        @property        def  license_latest(self):                try:                        return  self.version_set.latest().license                except  Version.DoesNotExist:                        return  "UNKNOWN"        def  grids(self):                return  (x.grid  for  x  in  self.gridpackage_set.all())        def  repo_name(self):                return  re.sub(self.repo.url_regex,  '',  self.repo_url)        def  participant_list(self):                return  self.participants.split(',')        def  get_usage_count(self):                return  self.usage.count()        def  commits_over_52(self):                now  =  datetime.now()                commits  =  Commit.objects.filter(                        package=self,                        commit_date__gt=now  -­  timedelta(weeks=52),                ).values_list('commit_date',  flat=True)                weeks  =  [0]  *  52                for  cdate  in  commits:                        age_weeks  =  (now  -­  cdate).days  //  7                        if  age_weeks  <  52:                                weeks[age_weeks]  +=  1                return  ','.join(map(str,  reversed(weeks)))        def  fetch_metadata(self,  *args,  **kwargs):                #  Get  the  downloads  from  pypi                if  self.pypi_url.strip()  and  self.pypi_url  !=  "http://pypi.python.org/pypi/":                        total_downloads  =  0                        for  release  in  fetch_releases(self.pypi_name):                                version,  created  =  Version.objects.get_or_create(                                        package=self,                                        number=release.version                                )                                #  add  to  total  downloads                                total_downloads  +=  release.downloads                                #  add  to  versions                                version.downloads  =  release.downloads                                if  hasattr(release,  "upload_time"):                                        version.upload_time  =  release.upload_time                                version.license  =  release.license                                version.hidden  =  release._pypi_hidden                                version.save()                        self.pypi_downloads  =  total_downloads                self.repo.fetch_metadata(self)                signal_fetch_latest_metadata.send(sender=self)                self.save()        def  save(self,  *args,  **kwargs):                if  not  self.repo_description:                        self.repo_description  =  ""                super(Package,  self).save(*args,  **kwargs)        def  fetch_commits(self):                self.repo.fetch_commits(self)        @property        def  last_released(self):                versions  =  self.version_set.exclude(upload_time=None)                if  versions:                        return  versions.latest()                return  None        @property        def  pypi_ancient(self):                release  =  self.last_released                if  release:                        return  release.upload_time  <  datetime.now()  -­  timedelta(365)                return  None        @property        def  no_development(self):                commit_date  =  self.last_updated                if  commit_date  is  not  None:                        return  commit_date  <  datetime.now()  -­  timedelta(365)                return  None        class  Meta:                ordering  =  ['title']                get_latest_by  =  'id'        def  __unicode__(self):                return  self.title        @models.permalink        def  get_absolute_url(self):                return  ("package",  [self.slug])

Slide 42

Slide 42 text

@pydanny [email protected] pro-tip Use Helper Functions

Slide 43

Slide 43 text

@pydanny [email protected] Using Helper Functions from  django.db  import  models   from  pies  import  utils  as  pie_utils     class  Pie(models.Model):          #  snip  all  the  attributes          def  is_savory(self):                return  pie_utils.is_savory(self.filling)          @property        def  cooking_time                return  pie_utils.cooking_time(self.filling)

Slide 44

Slide 44 text

@pydanny [email protected] Django’s API Conventions Encourage clean design

Slide 45

Slide 45 text

@pydanny [email protected] Content separation Presentation

Slide 46

Slide 46 text

@pydanny [email protected] Means We Don’t Fight So Much over Architecture

Slide 47

Slide 47 text

@pydanny [email protected] Get ings Done

Slide 48

Slide 48 text

Reason #4 Django has Awesome Views

Slide 49

Slide 49 text

@pydanny [email protected] Django Views are Functions HTTP Request HTTP Response Django View Function HttpResponse  =  view(HttpRequest()) Django is part of a group of Python frameworks that emerged around 2005 that embodied the readily-understood concept that HTTP requests could be handled via functions.

Slide 50

Slide 50 text

@pydanny [email protected] @login_required def  update_package(request,  slug):          package  =  get_object_or_404(Package,  slug=slug)        package.fetch_metadata()        package.fetch_commits()        msg  =  "Package  updated  successfully"        messages.add_message(request,  messages.INFO,  msg)          return  HttpResponseRedirect(        reverse("package",  kwargs={"slug":  package.slug}) ) Django Views are Functions #  Do  whatever  needs  to  be  done! #  Do  whatever  needs  to  be  done! #  Do  whatever  needs  to  be  done!

Slide 51

Slide 51 text

@pydanny [email protected] Django Views are Functions HTTP Request HTTP Response Django View Function HttpResponse  =  view(HttpRequest())

Slide 52

Slide 52 text

@pydanny [email protected] What about Class-Based Views?

Slide 53

Slide 53 text

@pydanny [email protected] View.as_view() What the heck does this mean?

Slide 54

Slide 54 text

@pydanny [email protected] class  View(object):        @classonlymethod        def  as_view(cls,  **initkwargs):                """                Main  entry  point  for  a  request-­response  process.                """                #  sanitize  keyword  arguments                for  key  in  initkwargs:                        if  key  in  cls.http_method_names:                                raise  TypeError("You  tried  to  pass  in  the  %s  method  name  as  a  "                                                                "keyword  argument  to  %s().  Don't  do  that."                                                                %  (key,  cls.__name__))                        if  not  hasattr(cls,  key):                                raise  TypeError("%s()  received  an  invalid  keyword  %r.  as_view  "                                                                "only  accepts  arguments  that  are  already  "                                                                "attributes  of  the  class."  %  (cls.__name__,  key))                def  view(request,  *args,  **kwargs):                        self  =  cls(**initkwargs)                        if  hasattr(self,  'get')  and  not  hasattr(self,  'head'):                                self.head  =  self.get                        self.request  =  request                        self.args  =  args                        self.kwargs  =  kwargs                        return  self.dispatch(request,  *args,  **kwargs)                #  take  name  and  docstring  from  class                update_wrapper(view,  cls,  updated=())                #  and  possible  attributes  set  by  decorators                #  like  csrf_exempt  from  dispatch                update_wrapper(view,  cls.dispatch,  assigned=())                return  view Returns a callable instance of the view Keyword control code For Python’s introspection tools

Slide 55

Slide 55 text

@pydanny [email protected] HttpResponse  =   View.as_view(HttpRequest())

Slide 56

Slide 56 text

@pydanny [email protected] Django Views are Functions HTTP Request HTTP Response Django View Class HttpResponse  =   View.as_view(HttpRequest())

Slide 57

Slide 57 text

Reason #5 Django has Awesome Longevity

Slide 58

Slide 58 text

@pydanny [email protected] Slow Deprecation Stable APIs make frameworks much nicer. They don’t just add longevity, they keep users happy.

Slide 59

Slide 59 text

@pydanny [email protected] from  django.db  import  models     class  Pie(models.Model):          STATUS_UNBAKED,  STATUS_BAKED  =  0,  1        FILLING_APPLE,  FILLING_MEAT  =  0,  1        STATUS_CHOICES  =  (                (STATUS_UNBAKED,  "Unbaked"),                (STATUS_BAKED,  "Baked")        )        FILLING_CHOICES  =  (                (FILLING_APPLE,  "Apple"),                (FILLING_MEAT,  "Meat"),        )          status  =  models.IntegerField(choices=STATUS_CHOICES,                                                  default=STATUS_UNBAKED)        filling  =  models.IntegerField(choices=FILLING_CHOICES)          def  __unicode__(self):                return  "{status}  {filling}  pie".format(                        status=self.get_status_display(),                        filling=self.get_filling_display()                ) Django 1.5 Django 1.4 Django 1.3 Django 1.2 Django 1.1 Django 1.0 Much of the same code works across years of Django. Backporting Django is easy, it’s Python that’s changed!

Slide 60

Slide 60 text

Reason #6 Django has Awesome Features

Slide 61

Slide 61 text

@pydanny [email protected] Django Features Admin Unicode XSS protection GeoDjango File Storage Prefetch related Aggregates Proxy Models Deferred Fields URL Namespaces New User Model Python 3 Multi-DB Model validation CSRF protection Object-level perms Email backends Natural Keys Template Caching Class Based Views Logging Static les Save Subsets Streaming Response Tests Con gurable on_delete TemplateResponse RequestFactory assertNumQueries Time zones Select for Update Password Hashing Signed Cookies WSGI Documented Caching

Slide 62

Slide 62 text

@pydanny [email protected] Admin Unicode XSS protection GeoDjango File Storage Prefetch related Aggregates Proxy Models Deferred Fields URL Namespaces New User Model Python 3 Multi-DB Model validation CSRF protection Object-level perms Email backends Natural Keys Template Caching Class Based Views Logging Static les Save Subsets Streaming Response Tests Con gurable on_delete TemplateResponse RequestFactory assertNumQueries Time zones Select for Update Password Hashing Signed Cookies WSGI Documented Caching Django Features

Slide 63

Slide 63 text

@pydanny [email protected] Django’s Admin is Awesome

Slide 64

Slide 64 text

@pydanny [email protected] django.contrib.admin a.k.a. How to sell Django 101

Slide 65

Slide 65 text

@pydanny [email protected] admin.py from  django.contrib  import  admin   from  pies.models  import  Pie   admin.site.register(Pie) Shortest Admin module possible. Remember it. Sweet, elegant, API awesomeness. What’s even better is there is a growing list of Django admin skins and themes being developed. If you are working on this sort of thing, keep it up please!

Slide 66

Slide 66 text

@pydanny [email protected] Pro-Tip django.contrib.admin + NoSQL

Slide 67

Slide 67 text

@pydanny [email protected] Don’t Extend django.contrib.admin

Slide 68

Slide 68 text

@pydanny [email protected] Write it from scratch. Easier Stable

Slide 69

Slide 69 text

@pydanny [email protected] MongoDB- avored #  myapp/mongoadmin.py   #  Import  the  MongoAdmin  base  class from  mongonaut.sites  import  MongoAdmin   #  Import  your  custom  models from  blog.models  import  Post   #  Instantiate  the  MongoAdmin  class #  Then  attach  the  mongoadmin  to  your  model Post.mongoadmin  =  MongoAdmin() https://github.com/pydanny/django-mongonaut

Slide 70

Slide 70 text

@pydanny [email protected] github.com/pydanny/django-mongonaut

Slide 71

Slide 71 text

@pydanny [email protected] admin2 #  myapp/admin2.py   #  Import  the  Admin2  base  class from  admin2.sites  import  Admin2   #  Import  your  custom  models from  blog.models  import  Post   #  Instantiate  the  Admin2  class #  Then  attach  the  admin2  to  your  model Post.admin2  =  Admin2() https://github.com/pydanny/django-mongonaut

Slide 72

Slide 72 text

@pydanny [email protected] github.com/pydanny/django-admin2

Slide 73

Slide 73 text

@pydanny [email protected] Admin Unicode XSS protection GeoDjango File Storage Prefetch related Aggregates Proxy Models Deferred Fields URL Namespaces New User Model Python 3 Multi-DB Model validation CSRF protection Object-level perms Email backends Natural Keys Template Caching Class Based Views Logging Static les Save Subsets Streaming Response Tests Con gurable on_delete TemplateResponse RequestFactory assertNumQueries Time zones Select for Update Password Hashing Signed Cookies WSGI Documented Caching Django Features Okay then, back to features.

Slide 74

Slide 74 text

@pydanny [email protected] Admin Unicode XSS protection GeoDjango File Storage Prefetch related Aggregates Proxy Models Deferred Fields URL Namespaces New User Model Python 3 Multi-DB Model validation CSRF protection Object-level perms Email backends Natural Keys Template Caching Class Based Views Logging Static les Save Subsets Streaming Response Tests Con gurable on_delete TemplateResponse RequestFactory assertNumQueries Time zones Select for Update Password Hashing Signed Cookies WSGI Documented Caching Django Features There’s a lot. So many that we just barely touch them in our book.

Slide 75

Slide 75 text

@pydanny [email protected] Next reason...

Slide 76

Slide 76 text

@pydanny [email protected] Reason #7 Django’s Full Stack is Awesome a.k.a. The section where the micro-framework fans go nuts. Seriously, hear me out.

Slide 77

Slide 77 text

@pydanny [email protected] Dominating Hackathons * according to pydanny Not having to worry about wifi. Documentation in one place.

Slide 78

Slide 78 text

@pydanny [email protected] Building Companies * according to pydanny

Slide 79

Slide 79 text

@pydanny [email protected] Today in Django Real projects being done in unextended Django & Python Standard Python/Django Libraries No concept of the larger Python/Django World

Slide 80

Slide 80 text

@pydanny [email protected] Really.

Slide 81

Slide 81 text

@pydanny [email protected] Late 2012 Los Angeles based eco-service company US$5,000,000 funding

Slide 82

Slide 82 text

@pydanny [email protected] No ird-Party Packages

Slide 83

Slide 83 text

@pydanny [email protected] Lots of Pain

Slide 84

Slide 84 text

@pydanny [email protected] Quite Pro table

Slide 85

Slide 85 text

@pydanny [email protected] oughts People building stuff with new tools under tight deadlines...

Slide 86

Slide 86 text

@pydanny [email protected] oughts Don’t always have time to investigate the community.

Slide 87

Slide 87 text

@pydanny [email protected] Django’s “ Full Stack” is a Win

Slide 88

Slide 88 text

@pydanny [email protected] On the ip side... They did a lot of work they didn’t need to do. What’s the solution?

Slide 89

Slide 89 text

@pydanny [email protected] Reason #8 Django has ousands of Awesome ird-Party Packages

Slide 90

Slide 90 text

@pydanny [email protected] How many Django speci c packages are there?

Slide 91

Slide 91 text

@pydanny [email protected] >>>  import  requests >>>  from  bs4  import  BeautifulSoup >>>  r  =  requests.get('https://pypi.python.org/pypi? %3Aaction=search&term=django&submit=search') >>>  soup  =  BeautifulSoup(r.content) >>>  t  =  soup.find("table",  class_="list") >>>  len(t.find_all('tr')) 4581 How many Django speci c packages are there?

Slide 92

Slide 92 text

@pydanny [email protected] Django is also Python! PyPI has over 30,000 Packages! If even 20% are generic enough to be imported into Python projects that’s awesome.

Slide 93

Slide 93 text

@pydanny [email protected] Reason #9 Django has Awesome Documentation

Slide 94

Slide 94 text

@pydanny [email protected] Culture of Documentation

Slide 95

Slide 95 text

@pydanny [email protected] Setting the Bar

Slide 96

Slide 96 text

@pydanny [email protected] Transcendental Django is Documentation

Slide 97

Slide 97 text

@pydanny [email protected] Reason #10 Django is Awesomely Humble

Slide 98

Slide 98 text

@pydanny [email protected] e Django Tradition of Invited Critical Talks • 2008 - Cal Henderson • 2010 - Eric Florenzano • 2011 - Glyph Lefkowitz, Steve Holden • 2012 - Kenneth Reitz, Justin Holmes At least this many talks, possibly more. Some were incredible, some were not.

Slide 99

Slide 99 text

@pydanny [email protected] Shaped the Code Base

Slide 100

Slide 100 text

@pydanny [email protected] Shaped the Core Team

Slide 101

Slide 101 text

@pydanny [email protected] Shaped the Community

Slide 102

Slide 102 text

@pydanny [email protected] Shaped Me I learned that inviting criticism of your work makes a difference. TSD is awesome because we ask people to be honest.

Slide 103

Slide 103 text

@pydanny [email protected] Reason #11 Django has an Awesome Community

Slide 104

Slide 104 text

@pydanny [email protected] For starters... “Django has brought more joy to my life than I thought was possible with a web framework.”

Slide 105

Slide 105 text

@pydanny [email protected] e Awesome Generosity of Django’s Community

Slide 106

Slide 106 text

@pydanny [email protected] Django’s Unwritten Rule of Generosity “ e more you help people in the Django/Python community, the more the community helps you.”

Slide 107

Slide 107 text

@pydanny [email protected] Case Study

Slide 108

Slide 108 text

@pydanny [email protected] http://2scoops.org

Slide 109

Slide 109 text

@pydanny [email protected] We didn’t do it alone. •9 General Technical Reviewers •3 Chapter Reviewers •116 Reader Contributors •2 Typesetting Experts While we stand on the shoulders of giants, over 125 people contributed directly to this book.

Slide 110

Slide 110 text

@pydanny [email protected] Gave the PDF of the book to developers in need who emailed us. This was especially helpful for developers in nations outside the normal monetary exchange.

Slide 111

Slide 111 text

@pydanny [email protected] In return we asked:

Slide 112

Slide 112 text

@pydanny [email protected] 1. Buy the book when possible.

Slide 113

Slide 113 text

@pydanny [email protected] 2. Give to Charity.

Slide 114

Slide 114 text

@pydanny [email protected] 3. Do something nice for someone.

Slide 115

Slide 115 text

@pydanny [email protected] What happened?

Slide 116

Slide 116 text

“As music is my main skill I have mentored a young student for free every Friday for an hour.” Ethan Lowman Instruction was a pattern... starting with outside skills

Slide 117

Slide 117 text

“I added Python and Django to the technical curriculum where I teach.” Herman Gonzales, Christopher Ayode, Pratyush Mittal Education was also a theme...

Slide 118

Slide 118 text

“I contributed to open source.” Jay, Nadia, Sam, Alex, Agustin, Guillaume, Paulo, Pedro, Roberto, Isaac, Nima, Eric, Hamid, Joe, Glan, Marc, Mark, Jared, Karl, Mohammed, Akshay, Ethan, Robert, Trung, Ivan, Cesar, Piotr, Andrii, Jin, June, Lucas, Samantha, Dan, Kenneth, Chris, Katherine, omas, Yoko, Gabriel, Keith, Renee, Edgar, Jamal, Christine, Alexandra, Eric, Steve, Carl, Mario, Francis, Antonio, Kapoor, Indra, David, Clay, Earnest, Pocholo, Matt, Daniela, Charles, Ananta, Vadim, Rashid, Jing, Tony, Neil, Mathieu, Cecilia, Aubrey, John, Cora,Fabio, Michael, Michelle, Alec, Sara, Sean, Ian, Bruce, Herman, Arne, Adam, Jeff, Allison, Ruth, Katy A lot of people contributed to open source efforts.

Slide 119

Slide 119 text

“I was able to donate $15 to Python 3 support in PyPy.” Juraj Bubniak Some people donated money.

Slide 120

Slide 120 text

“I bought a homeless man dinner.” Alex Wochna Others supported causes like feeding the hungry.

Slide 121

Slide 121 text

“I built a project for my church/mosque/temple/school.” Radic, Jaden, Luc, Wolfgang, Tobias, Richard, Ruth Lars, Jun, Bartek, Alex, Tyler, Pierre, Andreas, Julian ...working on worthy projects...

Slide 122

Slide 122 text

“I helped develop evidenceupload.org, which was used to send 2 GB of data to the FBI after the Boston Bombings.” Keith Donaldson ... and participating in current events.

Slide 123

Slide 123 text

@pydanny [email protected] People Took Our eme and Did Good Deeds.

Slide 124

Slide 124 text

@pydanny [email protected] ey were Awesome.

Slide 125

Slide 125 text

@pydanny [email protected] A Call to Action

Slide 126

Slide 126 text

@pydanny [email protected] Be Awesome. Change the world. That means make code, run events, write books. Do things that work, and make the world better.

Slide 127

Slide 127 text

@pydanny [email protected] One More ing... Cartwheel here

Slide 128

Slide 128 text

@pydanny [email protected] Finis