DjangoCon Europe 2013 Keynote

DjangoCon Europe 2013 Keynote

67e05420d4dd3492097aeb77f44f7867?s=128

Daniel Greenfeld

May 17, 2013
Tweet

Transcript

  1. 2.

    @pydanny pydanny@cartwheelweb.com Daniel Greenfeld Hi everyone. My name is Daniel

    Greenfeld. I’m the guy with the unenviable task of being the keynote after Brandon Rhodes.
  2. 4.

    @pydanny pydanny@cartwheelweb.com I work as a principal for Cartwheel Web,

    doing Python and Django. The company is named after cartwheels.
  3. 7.

    @pydanny pydanny@cartwheelweb.com 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.
  4. 11.

    @pydanny pydanny@cartwheelweb.com Example: “Class Based Views Suck” Saying this is

    easy. I used to say it all the time. Twitter, IRC, forums
  5. 15.

    @pydanny pydanny@cartwheelweb.com No one would remember Zed Shaw if he

    hadn’t written Learn Python the Hard Way* *Just one of many of his efforts.
  6. 17.

    @pydanny pydanny@cartwheelweb.com 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
  7. 18.
  8. 19.

    @pydanny pydanny@cartwheelweb.com 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.
  9. 22.

    @pydanny pydanny@cartwheelweb.com 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
  10. 23.

    @pydanny pydanny@cartwheelweb.com 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.
  11. 31.

    @pydanny pydanny@cartwheelweb.com 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.
  12. 33.

    @pydanny pydanny@cartwheelweb.com 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.
  13. 36.

    @pydanny pydanny@cartwheelweb.com 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.
  14. 37.

    @pydanny pydanny@cartwheelweb.com 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!
  15. 39.

    @pydanny pydanny@cartwheelweb.com 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.
  16. 41.

    @pydanny pydanny@cartwheelweb.com 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.<br  />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])
  17. 43.

    @pydanny pydanny@cartwheelweb.com 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)
  18. 49.

    @pydanny pydanny@cartwheelweb.com 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.
  19. 50.

    @pydanny pydanny@cartwheelweb.com @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!
  20. 51.

    @pydanny pydanny@cartwheelweb.com Django Views are Functions HTTP Request HTTP Response

    Django View Function HttpResponse  =  view(HttpRequest())
  21. 54.

    @pydanny pydanny@cartwheelweb.com 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
  22. 56.

    @pydanny pydanny@cartwheelweb.com Django Views are Functions HTTP Request HTTP Response

    Django View Class HttpResponse  =   View.as_view(HttpRequest())
  23. 58.
  24. 59.

    @pydanny pydanny@cartwheelweb.com 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!
  25. 61.

    @pydanny pydanny@cartwheelweb.com 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
  26. 62.

    @pydanny pydanny@cartwheelweb.com 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
  27. 65.

    @pydanny pydanny@cartwheelweb.com 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!
  28. 69.

    @pydanny pydanny@cartwheelweb.com 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
  29. 71.

    @pydanny pydanny@cartwheelweb.com 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
  30. 73.

    @pydanny pydanny@cartwheelweb.com 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.
  31. 74.

    @pydanny pydanny@cartwheelweb.com 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.
  32. 76.

    @pydanny pydanny@cartwheelweb.com Reason #7 Django’s Full Stack is Awesome a.k.a.

    The section where the micro-framework fans go nuts. Seriously, hear me out.
  33. 79.

    @pydanny pydanny@cartwheelweb.com Today in Django Real projects being done in

    unextended Django & Python Standard Python/Django Libraries No concept of the larger Python/Django World
  34. 88.

    @pydanny pydanny@cartwheelweb.com On the ip side... They did a lot

    of work they didn’t need to do. What’s the solution?
  35. 91.

    @pydanny pydanny@cartwheelweb.com >>>  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?
  36. 92.

    @pydanny pydanny@cartwheelweb.com 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.
  37. 98.

    @pydanny pydanny@cartwheelweb.com 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.
  38. 102.

    @pydanny pydanny@cartwheelweb.com Shaped Me I learned that inviting criticism of

    your work makes a difference. TSD is awesome because we ask people to be honest.
  39. 104.

    @pydanny pydanny@cartwheelweb.com For starters... “Django has brought more joy to

    my life than I thought was possible with a web framework.”
  40. 106.

    @pydanny pydanny@cartwheelweb.com Django’s Unwritten Rule of Generosity “ e more

    you help people in the Django/Python community, the more the community helps you.”
  41. 109.

    @pydanny pydanny@cartwheelweb.com 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.
  42. 110.

    @pydanny pydanny@cartwheelweb.com 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.
  43. 116.

    “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
  44. 117.

    “I added Python and Django to the technical curriculum where

    I teach.” Herman Gonzales, Christopher Ayode, Pratyush Mittal Education was also a theme...
  45. 118.

    “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.
  46. 119.

    “I was able to donate $15 to Python 3 support

    in PyPy.” Juraj Bubniak Some people donated money.
  47. 121.

    “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...
  48. 122.

    “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.
  49. 126.

    @pydanny pydanny@cartwheelweb.com Be Awesome. Change the world. That means make

    code, run events, write books. Do things that work, and make the world better.