Share
Embed
Transcript
128 slides
-
@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. -
@pydanny [email protected] I work as a principal for Cartwheel Web,
doing Python and Django. The company is named after cartwheels. -
@pydanny [email protected] http://2scoops.org Danny: 128,546++ Audrey: 121,871++ Co-wrote a book.
There is Audrey. She half of the book. -
@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. -
@pydanny [email protected] is Isn’t A Hate Django Talk. I’m not
giving one of those talks. Why not? -
@pydanny [email protected] Example: “Class Based Views Suck” Saying this is
easy. I used to say it all the time. Twitter, IRC, forums -
@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. -
@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 -
@pydanny [email protected] is Isn’t A Hate Django Talk. So no,
this isn’t a rant about Django. Instead... -
@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. -
@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 -
@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. -
@pydanny [email protected] Python shares the same rst two letters as
me. Python Pydanny -
@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. -
@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. -
@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. -
@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! -
@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. -
@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]) -
@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) -
@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. -
@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! -
@pydanny [email protected] Django Views are Functions HTTP Request HTTP Response
Django View Function HttpResponse = view(HttpRequest()) -
@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 -
@pydanny [email protected] Django Views are Functions HTTP Request HTTP Response
Django View Class HttpResponse = View.as_view(HttpRequest()) -
@pydanny [email protected] Slow Deprecation Stable APIs make frameworks much nicer.
They don’t just add longevity, they keep users happy. -
@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! -
@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 -
@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 -
@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! -
@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 -
@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 -
@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. -
@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. -
@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. -
@pydanny [email protected] Dominating Hackathons * according to pydanny Not having
to worry about wifi. Documentation in one place. -
@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 -
@pydanny [email protected] oughts People building stuff with new tools under
tight deadlines... -
@pydanny [email protected] On the ip side... They did a lot
of work they didn’t need to do. What’s the solution? -
@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? -
@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. -
@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. -
@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. -
@pydanny [email protected] For starters... “Django has brought more joy to
my life than I thought was possible with a web framework.” -
@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.” -
@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. -
@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. -
“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 -
“I added Python and Django to the technical curriculum where
I teach.” Herman Gonzales, Christopher Ayode, Pratyush Mittal Education was also a theme... -
“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. -
“I was able to donate $15 to Python 3 support
in PyPy.” Juraj Bubniak Some people donated money. -
“I bought a homeless man dinner.” Alex Wochna Others supported
causes like feeding the hungry. -
“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... -
“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. -
@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.