Powerful Generic Patterns With Django

10,055 views
9,859 views

Published on

A look into django's powerful content types framework and way to use in to reduce the complexity of large applications

Published in: Lifestyle, Business
0 Comments
21 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
10,055
On SlideShare
0
From Embeds
0
Number of Embeds
42
Actions
Shares
0
Downloads
174
Comments
0
Likes
21
Embeds 0
No embeds

No notes for slide

Powerful Generic Patterns With Django

  1. 1.
  2. 2. POWERFUL GENERIC PATTERNS<br />Django's Content Types Framework<br />
  3. 3. CONTENTTYPES<br />An application that can track all of the models installed in your Django-powered project, providing a high-level, generic interface for working with your models<br />
  4. 4. SAY WHAT ?<br />
  5. 5. CONTENTTYPES<br />----------------------------------------<br />| name | app_label | model |<br />| post | blogger | post |<br />| blog | blogger | Blog |<br />| like | likeable | Like |<br />----------------------------------------<br />
  6. 6. PROBLEM<br />blog = Blog.objects.get( pk = 1 )<br />posts = Post.objects.filter( blog = blog )<br />features = Post.objects.filter( feature = True )<br />3+ URLs<br />3+ view function<br />3+ templates<br />
  7. 7. PROBLEM<br />blog = Blog.objects.get( pk = 1 )<br />posts = Post.objects.filter( blog = blog )<br />features = Post.objects.filter( feature = True )<br />{%for post in posts %}<br />{{ post.title }} {{ post.like_set.count }} likes<br />{%endfor%}<br />
  8. 8. GENERIC VIEWS?<br />
  9. 9. GENERIC VIEWS?<br />Take certain common idioms and patterns found in view development and abstract them so that you can quickly write common views of data without having to write too much code<br />
  10. 10. GENERIC VIEWS?<br />from django.views.generic import list_detail<br />defmy_view( request ):<br />return list_detail.object_list( <br /> queryset=Post.objects.all()<br /> )<br />
  11. 11. NOT SO GENERIC VIEWS<br />from django.views.generic import list_detail<br />defmy_view( request ):<br />return list_detail.object_list( <br /> queryset=Post.objects.all()<br /> )<br />
  12. 12. NOT SO GENERIC VIEWS<br />
  13. 13. NOT SO GENERIC VIEWS<br />To Use A Generic View You Need...<br /><ul><li>A Queryset
  14. 14. A Model + ID
  15. 15. A Model + Slug
  16. 16. A Model + Slug Field</li></li></ul><li>MORE PROBLEMS<br />classPost(models.Model):<br /> title = models.CharField()<br /> blog = models.ForeignKey( Blog )<br /> body = models.TextField()<br /> slug = models.SlugField()<br /> likers = models.ForeignKey( User )<br /> likes = models.IntegerField()<br />Blog<br />Post<br />Post Likes<br />Post Likers<br />
  17. 17. MORE PROBLEMS<br />classFeature(models.Model):<br /> title = models.CharField()<br /> post = models.ForeignKey( Post )<br /> likers = models.ForeignKey( User )<br /> likes = models.IntegerField()<br />
  18. 18. CONTENTTYPES<br />An application that can track all of the models installed in your Django-powered project, providing a high-level, generic interface for working with your models<br />
  19. 19. CONTENTTYPES<br />Use the ORM without knowing what kind of objects you might be working with. <br />
  20. 20. CONTENTTYPES<br />Use the ORM without knowing what kind of objects you might be working with. <br />EVER.<br />
  21. 21. CONTENTTYPES<br />Your Model<br />ContentType<br />Model A<br />Model C<br />Model B<br />
  22. 22. GENERIC FOREIGNKEY<br />from django.contrib.contenttypes.models importContentTypefrom django.contrib.contenttypes importgeneric<br />classFeature(models.Model):<br /> content_type = models.ForeignKey (ContentType)<br /> object_id = models.PositiveIntegerField()<br /> content_object = generic.GenericForeignKey(<br />'content_type'<br /> ,'object_id'<br /> )<br />
  23. 23. MAGIC BITS<br />classFeature(models.Model):<br /> content_type = models.ForeignKey (ContentType)<br /> object_id = models.PositiveIntegerField()<br /> content_object = generic.GenericForeignKey( <br />'content_type'<br /> ,'object_id'<br /> )<br />
  24. 24. MAGIC BITS<br />classFeature(models.Model):<br /> content_type = models.ForeignKey (ContentType)<br /> object_id = models.PositiveIntegerField()<br /> content_object = generic.GenericForeignKey(<br />'content_type'<br /> ,'object_id'<br /> )<br />
  25. 25. MAGIC BITS<br />classFeature(models.Model):<br /> content_type = models.ForeignKey (ContentType)<br /> object_id = models.PositiveIntegerField()<br /> content_object = generic.GenericForeignKey(<br />'content_type'<br /> ,'object_id'<br /> )<br />
  26. 26. GENERIC FOREIGNKEY<br />>>> obj = Feature.objects.get( pk = 1 )<br />>>> obj.content_object<br />>>> <Post: Hello World><br />>>> obj = Feature.objects.get( pk = 2 )<br />>>> obj.content_object<br />>>> <Blog: The Best Blog><br />>>> obj = Feature.objects.get( pk = 3 )<br />>>> obj.content_object<br />>>> <Anything: Whatever You Want><br />
  27. 27. GENERIC FOREIGNKEY<br />
  28. 28. GENERIC FOREIGNKEY<br />classPost(models.Model):<br /> title = models.CharField()<br /> blog = models.ForeignKey( Blog )<br /> body = models.TextField()<br /> slug = models.SlugField()<br />classLike( models.Model ):<br /> content_type = models.ForeignKey( ContentType )<br /> object_id = models.PositiveIntegerField()<br /> content_object = generic.GenericForeignKey( ... )<br /> likers = models.ManyToMany( User )<br />
  29. 29. GOTCHA!<br />Models are NOT aware of their Content Type<br />
  30. 30. MORE PROBLEMS<br />classLike( models.Model ):<br /> content_type = models.ForeignKey( ContentType )<br /> object_id = models.PositiveIntegerField()<br /> content_object = generic.GenericForeignKey( ... )<br /> likers = models.ManyToMany( User )<br />
  31. 31. MORE PROBLEMS<br />classLike( models.Model ):<br /> content_type = models.ForeignKey( ContentType )<br /> object_id = models.PositiveIntegerField()<br /> content_object = generic.GenericForeignKey( ... )<br /> likers = models.ManyToMany( User )<br />deflike_view( request, object_id ):<br /> post = Post.objects.get( pk = object_id )<br /> like = Like( object_id = post, ??? )<br />
  32. 32. GENERIC GEMS<br />from django.contrib.contenttypes.models importContentType<br />from django.contrib.auth.models importUser<br />>>> type = ContentType.objects.get_for_model( User )<br />>>> type<br />>>> <ContentType: user ><br />>>> model = type.model_class()<br />>>> model<br />>>> <class: 'django.contrib.auth.models.User'><br />
  33. 33. GENERIC GEMS<br />
  34. 34. PATTERN #1<br />
  35. 35. PATTERN #1<br />Self-Aware Model<br />
  36. 36. SELF AWARE MODEL<br />classSelfAwareModel(models.Model): <br />def get_ct( self ):<br />''' Returns the Content Type for this instance'''<br />return ContentType.objects.get_for_model(self)<br />def get_ct_id( self ):<br />''' Returns the id of the content type for this instance'''<br />return self.get_ct().pk<br />def get_app_label( self ):<br />return self.get_ct().app_label<br />def get_model_name( self ):<br />return self.get_ct().model<br />classMeta:<br /> abstract = True<br />
  37. 37. SELF AWARE MODEL<br />classSelfAwareModel(models.Model): <br />def get_ct( self ):<br />''' Returns the Content Type for this instance'''<br />return ContentType.objects.get_for_model(self)<br />def get_ct_id( self ):<br />''' Returns the id of the content type for this instance'''<br />return self.get_ct().pk<br />def get_app_label( self ):<br />return self.get_ct().app_label<br />def get_model_name( self ):<br />return self.get_ct().model<br />classMeta:<br /> abstract = True<br />CACHED BY DJANGO<br />
  38. 38. SELF AWARE MODEL<br />classSelfAwareModel(models.Model): <br />def get_ct( self ):<br />''' Returns the Content Type for this instance'''<br />return ContentType.objects.get_for_model(self)<br />def get_ct_id( self ):<br />''' Returns the id of the content type for this instance'''<br />return self.get_ct().pk<br />def get_app_label( self ):<br />return self.get_ct().app_label<br />def get_model_name( self ):<br />return self.get_ct().model<br />classMeta:<br /> abstract = True<br />CACHED BY DJANGO<br />self.__class__._cache[self.db][key]<br />
  39. 39. SELF AWARE EVERYTHING<br />classPost( SelfAwareModel ):<br /> title = models.CharField()<br /> blog = models.ForeignKey( Blog )<br /> body = models.TextField()<br /> slug = models.SlugField()<br /> likers = models.ForeignKey( User )<br /> likes = models.IntegerField()<br />
  40. 40. SELF AWARE EVERYTHING<br />classPost( SelfAwareModel ):<br /> title = models.CharField()<br /> blog = models.ForeignKey( Blog )<br /> body = models.TextField()<br /> slug = models.SlugField()<br /> likers = models.ForeignKey( User )<br /> likes = models.IntegerField()<br />ALL MODELS<br />SUBCLASSE<br />SELFAWAREMODEL<br />
  41. 41. SELF AWARE EVERYTHING<br />classPost( SelfAwareModel ):<br /> title = models.CharField()<br /> blog = models.ForeignKey( Blog )<br /> body = models.TextField()<br /> slug = models.SlugField()<br /> likers = models.ForeignKey( User )<br /> likes = models.IntegerField()<br />@permalink<br />def get_absolute_url( self ):<br /> ...<br />>>> post = Post.objects.latest()<br />>>> obj.get_ct()<br />>>> <ContentType: post><br />
  42. 42. SELF AWARE EVERYTHING<br />classPost( SelfAwareModel ):<br /> title = models.CharField()<br /> blog = models.ForeignKey( Blog )<br /> body = models.TextField()<br /> slug = models.SlugField()<br /> likers = models.ForeignKey( User )<br /> likes = models.IntegerField()<br />@permalink<br />def get_absolute_url( self ):<br /> ...<br />I KNOW MY<br />CONTENT TYPE<br />>>> post = Post.objects.latest()<br />>>> obj.get_ct()<br />>>> <ContentType: post><br />
  43. 43. HOORAY!<br />
  44. 44. PATTERN #2<br />REAL Generic Views<br />
  45. 45. REAL GENERIC VIEW<br />defobject_list( request, ct_id ... ):<br /> type = ContentType.objects.get( pk = ct_id )<br /> model = type.model_class()<br /> obj_list = model._default_manager.all()<br />return render_to_response( ... )<br />
  46. 46. REAL GENERIC VIEW<br />defobject_detail( request, ct_id, obj_id, template=None ):<br /> type = ContentType.objects.get( pk = ct_id )<br /> model = type.model_class()<br /> obj = model._default_manager.get( pk = ct_id )<br />if template isNone:<br /> template = '%s_detail.html'%(type)<br />return render_to_response( template )<br />
  47. 47. REAL GENERIC VIEW<br />defobject_detail( request, ct_id, obj_id, template=None ):<br /> type = ContentType.objects.get( pk = ct_id )<br /> model = type.model_class()<br /> obj = model._default_manager.get( pk = ct_id )<br />if template isNone:<br /> template = '%s_detail.html'%(type)<br />return render_to_response( template )<br />
  48. 48. REAL GENERIC VIEW<br />defobject_detail( request, ct_id, obj_id, template=None ):<br /> type = ContentType.objects.get( pk = ct_id )<br /> model = type.model_class()<br /> obj = model._default_manager.get( pk = ct_id )<br />if template isNone:<br /> template = '%s_detail.html'%(type)<br />return render_to_response( template )<br />Might Want To Cache That<br />
  49. 49. REAL GENERIC VIEW<br />defobject_detail( request, ct_id, obj_id, template=None ):<br /> type = ContentType.objects.get( pk = ct_id )<br /> model = type.model_class()<br /> obj = model._default_manager.get( pk = ct_id )<br />if template isNone:<br /> template = '%s_detail.html'%(type)<br />return render_to_response( template )<br />Might Want To Cache That<br /><ul><li>self.__class__._cache[self.db][key]
  50. 50. cPickle & noSQL DB ( Redis )</li></li></ul><li>REAL GENERIC VIEW<br />project<br />|<br />| - likeables/<br />|<br />| - blog/<br /> |<br /> |- templates/<br /> |<br /> |- blog/<br /> | -post_list.html<br /> | -post_detail.html<br /> | -urls.py<br />|<br />| - templates/<br />| - object_list.html<br />| - object_detail.html<br />| - urls.py<br />
  51. 51. MORE PROBLEMS<br />Blog<br />Post<br />Post Likes<br />Post Likers<br />
  52. 52. MORE PROBLEMS<br />Blog<br />Post<br />Post Likers<br />Post Likes<br />
  53. 53. LESS PROBLEMS<br />LIKE<br />ContentType<br />POST<br />ANYTHING<br />FEATURE<br />
  54. 54. LIKE ANYTHING YOU WANT<br />
  55. 55. NOT BAD, KID!<br />
  56. 56. PATTERN #3<br />Universal URLs<br />
  57. 57. UNIVERSAL URLs<br />urlpatterns = patterns( 'myproj.myapp',<br /> url(<br /> r'^(?P<slug>[-w]+)/(?P<ct_id>d+)/list/$', <br />'object_list',<br />name='my_proj_content_list'<br /> ),<br /> url(<br /> r'^(?P<slug>[-w]+)/(?P<ct_id>d+)-(?P<obj_id>d+)/$',<br />'object_detail',<br />name="my_proj_content_detail"<br /> ),<br /> url(<br /> r'^(?P<slug>[-w]+)/(?P<ct_id>d+)-(?P<obj_id>d+)/edit/$',<br /> 'object_edit',<br />name="my_proj_content_edit"<br /> )<br /> ...<br />)<br />
  58. 58. UNIVERSAL URLs<br />/something-here/23/list/<br />/some-title/23-21/<br />/some-title/23-21/edit/<br />/some-title/23-21/delete/<br />/some-title/23-21/blah/<br />
  59. 59. PATTERN #4<br />Magic Forms<br />
  60. 60. MAGIC FORMS<br />defedit_object( request, ct_id, obj_id ):<br /> obj = utils.get_object( ct_id, obj_id )<br />
  61. 61. MAGIC FORMS<br />defedit_object( request, ct_id, obj_id ):<br /> obj = utils.get_object( ct_id, obj_id )<br /> form = ???<br />
  62. 62. MAGIC FORMS<br />defedit_object( request, ct_id, obj_id ):<br /> obj = utils.get_object( ct_id, obj_id )<br /> form = ???<br />Can't predefine ModelForm when you don't know what model you're working with<br />
  63. 63. MAGIC FORMS<br />
  64. 64. MAGIC FORMS<br />defform_class_for( obj, includes=[] excludes=[] ):<br /> modelclass = obj.get_ct().model_class()<br />class_MagicForm(forms.ModelForm):<br /> ...<br />classMeta:<br /> model= modelclass<br />if includes:<br /> fields = includes<br />if excludes:<br /> exclude = excludes <br />return _MagicForm<br />
  65. 65. MAGIC FORMS<br />defform_class_for( obj, includes=[] excludes=[] ):<br /> modelclass = obj.get_ct().model_class()<br />class_MagicForm(forms.ModelForm):<br /> ...<br />classMeta:<br /> model= modelclass<br />if includes:<br /> fields = includes<br />if excludes:<br /> exclude = excludes <br />return _MagicForm<br />DON'T KNOW<br />
  66. 66. MAGIC FORMS<br />defform_class_for( obj, includes=[] excludes=[] ):<br /> modelclass = obj.get_ct().model_class()<br />class_MagicForm(forms.ModelForm):<br /> ...<br />classMeta:<br /> model= modelclass<br />if includes:<br /> fields = includes<br />if excludes:<br /> exclude = excludes <br />return _MagicForm<br />DON'T<br />CARE <br />
  67. 67. MAGIC FORMS<br />defform_class_for( obj, includes=[] excludes=[] ):<br /> modelclass = obj.get_ct().model_class()<br />class_MagicForm(forms.ModelForm):<br /> ...<br />classMeta:<br /> model= modelclass<br />if includes:<br /> fields = includes<br />if excludes:<br /> exclude = excludes <br />return _MagicForm<br />PERFECTLY<br />LEGAL<br />
  68. 68. FULL CIRCLE<br />defedit_object( request, ct_id, obj_id ):<br /> obj = utils.get_object( ct_id, obj_id )<br /> formclass = utils.get_form_for( obj )<br /> form = formclass()<br />return render_to_response( ... {'form':form} )<br />
  69. 69. FULL CIRCLE<br />defedit_object( request, ct_id, obj_id ):<br /> obj = utils.get_object( ct_id, obj_id )<br /> formclass = utils.get_form_for( obj )<br /> form = formclass()<br />return render_to_response( ... {'form':form} )<br />DON'T KNOW<br />
  70. 70. FULL CIRCLE<br />defedit_object( request, ct_id, obj_id ):<br /> obj = utils.get_object( ct_id, obj_id )<br /> formclass = utils.get_form_for( obj )<br /> form = formclass()<br />return render_to_response( ... {'form':form} )<br />DON'T<br />CARE <br />
  71. 71. DEAD SIMPLE<br />{%urlmy_proj_content_list ct_id=obj.get_ct_id %}<br />{%urlmy_proj_content_detail<br /> slug=obj.slug, ct_id=obj.get_ct_id, obj_id=obj.pk %}<br />{%urlmy_proj_content_edit<br /> slug=obj.slug, ct_id=obj.get_ct_id, obj_id=obj.pk %}<br />
  72. 72. FOR THE WIN<br />
  73. 73. SCALE IT OUT<br />Define A Model<br />Sync DB<br />Make A Template ( Maybe ? )<br />Rinse <br />Repeate<br />
  74. 74. PATTERNS RECAP<br /><ul><li>Self Aware Models
  75. 75. Better Generic Views & utilities
  76. 76. Universial URLs
  77. 77. Magic Forms</li></li></ul><li>PATTERNS RECAP<br /><ul><li>Self Aware Models
  78. 78. Better Generic Views & utilities
  79. 79. Universial URLs
  80. 80. Magic Forms</li></ul>You can perform CRUD ops and create any kind of relationship on any kind of object at anytimewithout programming for every situation.<br />
  81. 81. FIN<br />

×