Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DjangoCon Europe 2013 Keynote

DjangoCon Europe 2013 Keynote

Daniel Greenfeld

May 17, 2013
Tweet

More Decks by Daniel Greenfeld

Other Decks in Technology

Transcript

  1. @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.
  2. @pydanny [email protected] I work as a principal for Cartwheel Web,

    doing Python and Django. The company is named after cartwheels.
  3. @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.
  4. @pydanny [email protected] Example: “Class Based Views Suck” Saying this is

    easy. I used to say it all the time. Twitter, IRC, forums
  5. @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.
  6. @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
  7. @pydanny [email protected] is Isn’t A Hate Django Talk. So no,

    this isn’t a rant about Django. Instead...
  8. @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.
  9. @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
  10. @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.
  11. @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.
  12. @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.
  13. @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.
  14. @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!
  15. @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.
  16. @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.<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. @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)
  18. @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.
  19. @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!
  20. @pydanny [email protected] Django Views are Functions HTTP Request HTTP Response

    Django View Function HttpResponse  =  view(HttpRequest())
  21. @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
  22. @pydanny [email protected] Django Views are Functions HTTP Request HTTP Response

    Django View Class HttpResponse  =   View.as_view(HttpRequest())
  23. @pydanny [email protected] Slow Deprecation Stable APIs make frameworks much nicer.

    They don’t just add longevity, they keep users happy.
  24. @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!
  25. @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
  26. @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
  27. @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!
  28. @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
  29. @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
  30. @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.
  31. @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.
  32. @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.
  33. @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
  34. @pydanny [email protected] On the ip side... They did a lot

    of work they didn’t need to do. What’s the solution?
  35. @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?
  36. @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.
  37. @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.
  38. @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.
  39. @pydanny [email protected] For starters... “Django has brought more joy to

    my life than I thought was possible with a web framework.”
  40. @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.”
  41. @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.
  42. @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.
  43. “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. “I added Python and Django to the technical curriculum where

    I teach.” Herman Gonzales, Christopher Ayode, Pratyush Mittal Education was also a theme...
  45. “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. “I was able to donate $15 to Python 3 support

    in PyPy.” Juraj Bubniak Some people donated money.
  47. “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. “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. @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.