├── books ├── books │ ├── __init__.py │ ├── wsgi.py │ ├── urls.py │ └── settings.py ├── .gitignore ├── booksite │ ├── __init__.py │ ├── tests.py │ ├── static │ │ ├── bootstrap │ │ │ ├── img │ │ │ │ ├── glyphicons-halflings.png │ │ │ │ └── glyphicons-halflings-white.png │ │ │ ├── js │ │ │ │ ├── bootstrap.min.js │ │ │ │ └── bootstrap.js │ │ │ └── css │ │ │ │ └── bootstrap-responsive.css │ │ └── jquery │ │ │ └── js │ │ │ ├── jquery.formset.min.js │ │ │ └── jquery-1.8.2.min.js │ ├── forms.py │ ├── admin.py │ ├── models.py │ ├── templates │ │ ├── index.html │ │ ├── manage_authors.html │ │ └── base.html │ └── views.py ├── manage.py └── README.md ├── django.pdf ├── .gitignore ├── requirements.txt └── README.md /books/books/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /books/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite3 -------------------------------------------------------------------------------- /books/booksite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rg3915/django/master/django.pdf -------------------------------------------------------------------------------- /books/booksite/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.nav 2 | *.snm 3 | *.vrb 4 | *.pyc 5 | *.db 6 | *.sqlite3 7 | 8 | bin/ 9 | include/ 10 | lib/ 11 | local/ -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.6.6 2 | argparse==1.2.1 3 | django-debug-toolbar==1.2.1 4 | django-forms-bootstrap==3.0.0 5 | sqlparse==0.1.11 6 | wsgiref==0.1.2 7 | -------------------------------------------------------------------------------- /books/booksite/static/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rg3915/django/master/books/booksite/static/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /books/booksite/static/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rg3915/django/master/books/booksite/static/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /books/booksite/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django import forms 3 | from .models import Author 4 | 5 | 6 | class AuthorForm(forms.ModelForm): 7 | 8 | class Meta: 9 | model = Author 10 | -------------------------------------------------------------------------------- /books/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "books.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /books/booksite/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from models import * 3 | 4 | 5 | class BookInline(admin.TabularInline): 6 | model = Book 7 | 8 | 9 | class AuthorAdmin(admin.ModelAdmin): 10 | inlines = [ 11 | BookInline, 12 | ] 13 | list_display = ('name',) 14 | 15 | admin.site.register(Author, AuthorAdmin) 16 | -------------------------------------------------------------------------------- /books/books/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for books project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "books.settings") 12 | 13 | from django.core.wsgi import get_wsgi_application 14 | application = get_wsgi_application() 15 | -------------------------------------------------------------------------------- /books/books/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from booksite.views import * 3 | 4 | from django.contrib import admin 5 | admin.autodiscover() 6 | 7 | urlpatterns = patterns( 8 | 'booksite.views', 9 | url(r'^$', 'authors_list'), 10 | url(r'^author/add/$', 'author_add'), 11 | url(r'^author/edit/(?P\d+)$', 'author_edit'), 12 | url(r'^author/delete/(?P\d+)$', 'author_delete'), 13 | url(r'^admin/', include(admin.site.urls)), 14 | ) 15 | -------------------------------------------------------------------------------- /books/booksite/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.db import models 3 | 4 | 5 | class Author(models.Model): 6 | name = models.CharField(max_length=100) 7 | 8 | 9 | class Book(models.Model): 10 | CATEGORIES = [ 11 | ('romance', 'Romance'), 12 | ('fiction', u'Ficção'), 13 | ('suspense', 'Suspense') 14 | ] 15 | author = models.ForeignKey(Author) 16 | title = models.CharField(max_length=100) 17 | category = models.CharField(max_length=50, choices=CATEGORIES) 18 | -------------------------------------------------------------------------------- /books/booksite/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |

Lista de Autores

5 |

Adicionar

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for author in object_list %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% endfor %} 24 | 25 |
IDNomeQtde de livrosDeletar?
{{ author.id }}{{ author.name }}{{ author.book_set.count }}Deletar
26 | 27 | {% endblock %} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Django 2 | ====== 3 | 4 | # Objetivo 5 | 6 | O objetivo deste projeto é experimentar e testar o framework Django. O django.pdf é uma apresentação feita na faculdade. 7 | 8 | # Convenções 9 | 10 | **Título de entidades**: primeira maiúscula e no singular. Ex: *Veiculo, Pedido, Usuario, Vendedor*. 11 | 12 | **Classes**: em nomes compostos maiúscula e juntas. Ex: *ListarProduto, AdicionarProduto* ([PEP 8][4]). 13 | 14 | **Funções**: nomes compostos minúsculos e separados com underline. Ex: *listar_produto, adicionar_produto* ([PEP 8][4]). 15 | 16 | **Templates**: usar a mesma convenção. Ex: *listar_produto.html, adicionar_produto.html*. 17 | 18 | # Books 19 | 20 | Projeto inicial para alguns testes. 21 | 22 | ### Referências: 23 | 24 | [Django Project][0] 25 | 26 | [Django Brasil][1] 27 | 28 | [Alex Dzul][2] 29 | 30 | [Welcome To The Django][3] 31 | 32 | [GoDjango][5] 33 | 34 | [Coding for Entrepreneurs][6] 35 | 36 | [0]: https://www.djangoproject.com/ 37 | [1]: http://www.djangobrasil.org/ 38 | [2]: http://www.youtube.com/playlist?list=PL2670DAAFCFECA138 39 | [3]: http://welcometothedjango.com.br/ 40 | [4]: http://www.python.org.br/wiki/GuiaDeEstilo 41 | [5]: https://godjango.com/ 42 | [6]: http://codingforentrepreneurs.com/ -------------------------------------------------------------------------------- /books/README.md: -------------------------------------------------------------------------------- 1 | [inline formset links.txt][0] 2 | 3 | [https://djangosnippets.org/snippets/1246/][1] 4 | 5 | [inlineformset template][2] 6 | 7 | [Create multiple related objects at once][3] 8 | 9 | [Dynamically Add Form to Formset Using JavaScript and Django][4] 10 | 11 | [django-dynamic-formset][5] 12 | 13 | [Django Inline Formset Example][6] 14 | 15 | [django crispy forms and django inline forms example (inlineformset_factory)][7] 16 | 17 | [como-alterar-campo-formulario-em-um-inline-formset][8] 18 | 19 | [Django class-based views with multiple inline formsets][9] 20 | 21 | [0]: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets 22 | [1]: https://djangosnippets.org/snippets/1246/ 23 | [2]: https://djangosnippets.org/snippets/1182/ 24 | [3]: https://djangosnippets.org/snippets/1399/ 25 | [4]: http://stellarchariot.com/blog/2011/02/dynamically-add-form-to-formset-using-javascript-and-django/ 26 | [5]: https://code.google.com/p/django-dynamic-formset/ 27 | [6]: https://github.com/epicserve/inlineformset-example 28 | [7]: https://gist.github.com/ibarovic/3092910 29 | [8]: http://imasters.com.br/linguagens/py/como-alterar-campo-formulario-em-um-inline-formset/ 30 | [9]: http://kevindias.com/writing/django-class-based-views-multiple-inline-formsets/ -------------------------------------------------------------------------------- /books/booksite/templates/manage_authors.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load bootstrap_tags %} 3 | 4 | {% block js %} 5 | 6 | 13 | {% endblock %} 14 | 15 | {% block content %} 16 |

Crie ou edite seu autor e seus livros

17 |
18 | {% csrf_token %} 19 | {{ form|as_bootstrap }} 20 | {{ formset.management_form }} 21 | 22 | {{ formset.non_form_errors.as_ul }} 23 | 24 | {% for form in formset.forms %} 25 | {% if forloop.first %} 26 | 27 | {% for field in form.visible_fields %} 28 | 29 | {% endfor %} 30 | 31 | {% endif %} 32 | 33 | 34 | {% for field in form.visible_fields %} 35 | 44 | {% endfor %} 45 | 46 | 47 | {% endfor %} 48 |
{{ field.label|capfirst }}
36 | {% if forloop.first %} 37 | {% for hidden in form.hidden_fields %} 38 | {{ hidden }} 39 | {% endfor %} 40 | {% endif %} 41 | {{ field.errors.as_ul }} 42 | {{ field }} 43 |
49 | 50 |
51 | {% endblock %} -------------------------------------------------------------------------------- /books/booksite/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | InlineFormset 6 | 7 | 8 | 9 | 10 | 11 | {% block css %}{% endblock %} 12 | {% block js %}{% endblock %} 13 | 14 | 15 | 16 | 35 |
36 | {% block content %}{% endblock %} 37 |
38 |
39 |
40 |

Topo

41 |
42 |
43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /books/booksite/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # http://imasters.com.br/linguagens/py/como-alterar-campo-formulario-em-um-inline-formset/ 3 | from models import Author, Book 4 | from forms import AuthorForm 5 | from django.template import RequestContext 6 | from django.http import HttpResponseRedirect 7 | from django.shortcuts import render_to_response 8 | from django.forms.models import inlineformset_factory 9 | from django.views.generic.list_detail import object_list 10 | 11 | 12 | def authors_list(request): 13 | authors = Author.objects.all() 14 | return object_list(request, queryset=authors, template_name="index.html") 15 | 16 | 17 | def author_delete(request, pk): 18 | Author.objects.get(pk=pk).delete() 19 | return HttpResponseRedirect('/inlines/') 20 | 21 | 22 | def author_add(request): 23 | author = Author() 24 | return author_manager(request, author) 25 | 26 | 27 | def author_edit(request, pk): 28 | author = Author.objects.get(pk=pk) 29 | return author_manager(request, author) 30 | 31 | 32 | def author_manager(request, author): 33 | BookInlineFormSet = inlineformset_factory(Author, Book, extra=1, 34 | formfield_callback=add_category) 35 | 36 | form = AuthorForm(request.POST or None, instance=author) 37 | formset = BookInlineFormSet(request.POST or None, instance=author) 38 | 39 | if form.is_valid() and formset.is_valid(): 40 | form.save() 41 | formset.save() 42 | return HttpResponseRedirect('/inlines/') 43 | 44 | return render_to_response("manage_authors.html", 45 | {"formset": formset, 46 | "form": form}, 47 | RequestContext(request)) 48 | 49 | 50 | def add_category(field, **kwargs): 51 | if field.name == 'category': 52 | additional_choices = [ 53 | ('best_seller', 'Best Seller'), 54 | ('self_help', 'Auto Ajuda') 55 | ] 56 | for choice in additional_choices: 57 | if not choice in field.choices: 58 | field.choices.extend(additional_choices) 59 | return field.formfield(**kwargs) 60 | -------------------------------------------------------------------------------- /books/books/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for books project. 3 | 4 | For more information on this file, see 5 | https://docs.djangoproject.com/en/1.6/topics/settings/ 6 | 7 | For the full list of settings and their values, see 8 | https://docs.djangoproject.com/en/1.6/ref/settings/ 9 | """ 10 | 11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 12 | import os 13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__)) 14 | 15 | 16 | # Quick-start development settings - unsuitable for production 17 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ 18 | 19 | # SECURITY WARNING: keep the secret key used in production secret! 20 | SECRET_KEY = '#s*fqlqj)+#*64+)n@a8mf74&rq@6wm1x9xv$-tmbiq$arvf@d' 21 | 22 | # SECURITY WARNING: don't run with debug turned on in production! 23 | DEBUG = True 24 | 25 | TEMPLATE_DEBUG = True 26 | 27 | ALLOWED_HOSTS = [] 28 | 29 | 30 | # Application definition 31 | 32 | INSTALLED_APPS = ( 33 | 'django.contrib.admin', 34 | 'django.contrib.auth', 35 | 'django.contrib.contenttypes', 36 | 'django.contrib.sessions', 37 | 'django.contrib.messages', 38 | 'django.contrib.staticfiles', 39 | 'booksite', 40 | ) 41 | 42 | MIDDLEWARE_CLASSES = ( 43 | 'django.contrib.sessions.middleware.SessionMiddleware', 44 | 'django.middleware.common.CommonMiddleware', 45 | 'django.middleware.csrf.CsrfViewMiddleware', 46 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 47 | 'django.contrib.messages.middleware.MessageMiddleware', 48 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 49 | ) 50 | 51 | ROOT_URLCONF = 'books.urls' 52 | 53 | WSGI_APPLICATION = 'books.wsgi.application' 54 | 55 | 56 | # Database 57 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases 58 | 59 | DATABASES = { 60 | 'default': { 61 | 'ENGINE': 'django.db.backends.sqlite3', 62 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 63 | } 64 | } 65 | 66 | # Internationalization 67 | # https://docs.djangoproject.com/en/1.6/topics/i18n/ 68 | 69 | LANGUAGE_CODE = 'pt-br' 70 | 71 | TIME_ZONE = 'UTC' 72 | 73 | USE_I18N = True 74 | 75 | USE_L10N = True 76 | 77 | USE_TZ = True 78 | 79 | 80 | # Static files (CSS, JavaScript, Images) 81 | # https://docs.djangoproject.com/en/1.6/howto/static-files/ 82 | 83 | STATIC_URL = '/static/' 84 | -------------------------------------------------------------------------------- /books/booksite/static/jquery/js/jquery.formset.min.js: -------------------------------------------------------------------------------- 1 | ;(function($){$.fn.formset=function(opts) 2 | {var options=$.extend({},$.fn.formset.defaults,opts),flatExtraClasses=options.extraClasses.join(' '),$$=$(this),applyExtraClasses=function(row,ndx){if(options.extraClasses){row.removeClass(flatExtraClasses);row.addClass(options.extraClasses[ndx%options.extraClasses.length]);}},updateElementIndex=function(elem,prefix,ndx){var idRegex=new RegExp('('+prefix+'-\\d+-)|(^)'),replacement=prefix+'-'+ndx+'-';if(elem.attr("for"))elem.attr("for",elem.attr("for").replace(idRegex,replacement));if(elem.attr('id'))elem.attr('id',elem.attr('id').replace(idRegex,replacement));if(elem.attr('name'))elem.attr('name',elem.attr('name').replace(idRegex,replacement));},hasChildElements=function(row){return row.find('input,select,textarea,label').length>0;},insertDeleteLink=function(row){if(row.is('TR')){row.children(':last').append(''+options.deleteText+'');}else if(row.is('UL')||row.is('OL')){row.append('
  • '+options.deleteText+'
  • ');}else{row.append(''+options.deleteText+'');} 3 | row.find('a.'+options.deleteCssClass).click(function(){var row=$(this).parents('.'+options.formCssClass),del=row.find('input:hidden[id $= "-DELETE"]');if(del.length){del.val('on');row.hide();}else{row.remove();var forms=$('.'+options.formCssClass).not('.formset-custom-template');$('#id_'+options.prefix+'-TOTAL_FORMS').val(forms.length);for(var i=0,formCount=forms.length;i');del.remove();} 5 | if(hasChildElements(row)){insertDeleteLink(row);row.addClass(options.formCssClass);applyExtraClasses(row,i);}});if($$.length){var addButton,template;if(options.formTemplate){template=(options.formTemplate instanceof $)?options.formTemplate:$(options.formTemplate);template.removeAttr('id').addClass(options.formCssClass).addClass('formset-custom-template');template.find('input,select,textarea,label').each(function(){updateElementIndex($(this),options.prefix,2012);});insertDeleteLink(template);}else{template=$('.'+options.formCssClass+':last').clone(true).removeAttr('id');template.find('input:hidden[id $= "-DELETE"]').remove();template.find('input,select,textarea,label').each(function(){var elem=$(this);if(elem.is('input:checkbox')||elem.is('input:radio')){elem.attr('checked',false);}else{elem.val('');}});} 6 | options.formTemplate=template;if($$.attr('tagName')=='TR'){var numCols=$$.eq(0).children().length;$$.parent().append(''+options.addText+'');addButton=$$.parent().find('tr:last a');addButton.parents('tr').addClass(options.formCssClass+'-add');}else{$$.filter(':last').after(''+options.addText+'');addButton=$$.filter(':last').next();} 7 | addButton.click(function(){var formCount=parseInt($('#id_'+options.prefix+'-TOTAL_FORMS').val()),row=options.formTemplate.clone(true).removeClass('formset-custom-template'),buttonRow=$(this).parents('tr.'+options.formCssClass+'-add').get(0)||this;applyExtraClasses(row,formCount);row.insertBefore($(buttonRow)).show();row.find('input,select,textarea,label').each(function(){updateElementIndex($(this),options.prefix,formCount);});$('#id_'+options.prefix+'-TOTAL_FORMS').val(formCount+1);if(options.added)options.added(row);return false;});} 8 | return $$;} 9 | $.fn.formset.defaults={prefix:'form',formTemplate:null,addText:'add another',deleteText:'remove',addCssClass:'add-row',deleteCssClass:'delete-row',formCssClass:'dynamic-form',extraClasses:[],added:null,removed:null};})(jQuery) -------------------------------------------------------------------------------- /books/booksite/static/bootstrap/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap.js by @fat & @mdo 3 | * plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-scrollspy.js, bootstrap-tab.js, bootstrap-tooltip.js, bootstrap-popover.js, bootstrap-affix.js, bootstrap-alert.js, bootstrap-button.js, bootstrap-collapse.js, bootstrap-carousel.js, bootstrap-typeahead.js 4 | * Copyright 2012 Twitter, Inc. 5 | * http://www.apache.org/licenses/LICENSE-2.0.txt 6 | */ 7 | !function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(a){this.$element.hide().trigger("hidden"),this.backdrop()},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('