├── full.sh ├── ideal.sh ├── basic ├── myproject │ ├── __init__.py │ ├── core │ │ ├── __init__.py │ │ ├── migrations │ │ │ ├── __init__.py │ │ │ ├── 0006_auto_20170126_2311.py │ │ │ ├── 0005_person_slug.py │ │ │ ├── 0002_auto_20161128_1711.py │ │ │ ├── 0004_auto_20161128_1810.py │ │ │ ├── 0001_initial.py │ │ │ └── 0003_auto_20161128_1801.py │ │ ├── apps.py │ │ ├── tests │ │ │ ├── test_view_home.py │ │ │ ├── __init__.py │ │ │ └── test_model_person.py │ │ ├── templates │ │ │ ├── core │ │ │ │ ├── person_form.html │ │ │ │ ├── person_list.html │ │ │ │ └── person_detail.html │ │ │ ├── nav.html │ │ │ ├── index.html │ │ │ ├── footer.html │ │ │ ├── pagination.html │ │ │ └── base.html │ │ ├── urls.py │ │ ├── forms.py │ │ ├── lists.py │ │ ├── admin.py │ │ ├── static │ │ │ └── css │ │ │ │ ├── main.css │ │ │ │ └── social.css │ │ ├── views.py │ │ └── models.py │ ├── urls.py │ ├── wsgi.py │ ├── selenium │ │ ├── gen_names.py │ │ ├── gen_random_values.py │ │ ├── selenium_person.py │ │ └── gen_address.py │ ├── fixtures │ │ └── shell_person.py │ └── settings.py ├── requirements │ ├── base.txt │ ├── dev.txt │ └── prod.txt ├── requirements.txt ├── manage.py ├── Makefile └── fixtures.json ├── .gitignore ├── README.md ├── Makefile ├── _test_mixer.py ├── basic.sh ├── minimal.sh └── setupfull.sh /full.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ideal.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basic/myproject/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basic/requirements/base.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basic/myproject/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basic/myproject/core/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basic/requirements.txt: -------------------------------------------------------------------------------- 1 | -r requirements/dev.txt -------------------------------------------------------------------------------- /basic/requirements/dev.txt: -------------------------------------------------------------------------------- 1 | -r base.txt 2 | django-debug-toolbar>=1.4 -------------------------------------------------------------------------------- /basic/requirements/prod.txt: -------------------------------------------------------------------------------- 1 | -r base.txt 2 | gunicorn>=19.6 3 | psycopg2>=2.6 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | *.sqlite3 4 | *.env 5 | *.DS_Store 6 | .venv/ 7 | staticfiles/ 8 | .ipynb_checkpoints/ 9 | -------------------------------------------------------------------------------- /basic/myproject/core/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CoreConfig(AppConfig): 5 | name = 'core' 6 | -------------------------------------------------------------------------------- /basic/myproject/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from django.contrib import admin 3 | 4 | urlpatterns = [ 5 | url(r'', include('myproject.core.urls', namespace='core')), 6 | url(r'^admin/', admin.site.urls), 7 | ] 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boilerplate 2 | 3 | Is a test to create Django project with full shell script. 4 | 5 | `Django==1.10.x` 6 | 7 | * [X] minimal 8 | 9 | ``` 10 | source minimal.sh 11 | ``` 12 | 13 | * [ ] basic 14 | * [ ] ideal 15 | * [ ] full 16 | -------------------------------------------------------------------------------- /basic/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", "myproject.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | pip install -r requirements.txt 3 | 4 | createuser: 5 | ./manage.py createsuperuser --username='admin' --email='' 6 | 7 | clear: 8 | rm -rf myproject 9 | rm -rf __pycache__ 10 | rm -rf contrib 11 | rm -f db.sqlite3 12 | rm -f .env 13 | rm -f manage.py 14 | rm -f requirements.txt 15 | -------------------------------------------------------------------------------- /basic/Makefile: -------------------------------------------------------------------------------- 1 | migrate: 2 | python manage.py makemigrations 3 | python manage.py migrate 4 | 5 | selenium_person: 6 | python myproject/selenium/selenium_person.py 7 | 8 | shell_person: 9 | python manage.py shell < myproject/fixtures/shell_person.py 10 | 11 | backup: 12 | python manage.py dumpdata --format=json --indent=2 > fixtures.json 13 | 14 | load: 15 | python manage.py loaddata fixtures.json 16 | 17 | run: 18 | python manage.py runserver 19 | -------------------------------------------------------------------------------- /basic/myproject/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for myproject 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.9/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /basic/myproject/core/tests/test_view_home.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | 4 | class HomeTest(TestCase): 5 | 6 | def setUp(self): 7 | self.resp = self.client.get('/') 8 | 9 | def test_get(self): 10 | ''' get / deve retornar status code 200. ''' 11 | self.assertEqual(200, self.resp.status_code) 12 | 13 | def test_template(self): 14 | ''' Home deve usar template index.html ''' 15 | self.assertTemplateUsed(self.resp, 'index.html') 16 | -------------------------------------------------------------------------------- /basic/myproject/core/tests/__init__.py: -------------------------------------------------------------------------------- 1 | PERSON_DATA = { 2 | 'gender': 'M', 3 | 'treatment': 'sr', 4 | 'first_name': 'Regis', 5 | 'last_name': 'Santos', 6 | 'slug': 'regis-santos', 7 | 'birthday': '1985-12-01 02:42:30+00:00', 8 | 'email': 'regis@example.com', 9 | 'cpf': '75873211795', 10 | 'address': u'Rua São Leopoldo, 101', 11 | 'complement': 'Apto 303', 12 | 'district': u'Belezinho', 13 | 'city': u'São Paulo', 14 | 'uf': 'SP', 15 | 'cep': '03055000', 16 | 'blocked': False, 17 | } 18 | -------------------------------------------------------------------------------- /basic/myproject/core/migrations/0006_auto_20170126_2311.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.5 on 2017-01-26 23:11 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('core', '0005_person_slug'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='person', 17 | name='slug', 18 | field=models.SlugField(verbose_name='slug'), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /basic/myproject/core/migrations/0005_person_slug.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.5 on 2017-01-12 00:39 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('core', '0004_auto_20161128_1810'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='person', 17 | name='slug', 18 | field=models.SlugField(blank=True, verbose_name='slug'), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /basic/myproject/core/templates/core/person_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load bootstrap %} 4 | 5 | {% block title %}Person Form{% endblock title %} 6 | 7 | {% block content %} 8 | 9 |
10 | Add Contact 11 | {% csrf_token %} 12 | {{ form|bootstrap_horizontal }} 13 | 14 |
15 |
16 | 17 |
18 |
19 |
20 | 21 | {% endblock content %} 22 | -------------------------------------------------------------------------------- /basic/myproject/core/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from myproject.core import views as c 3 | 4 | person_patterns = [ 5 | url(r'^$', c.PersonList.as_view(), name='person_list'), 6 | url(r'^add/$', c.PersonCreate.as_view(), name='person_add'), 7 | url(r'^(?P[\w-]+)/$', c.person_detail, name='person_detail'), 8 | url(r'^(?P[\w-]+)/edit/$', c.person_update, name='person_edit'), 9 | url(r'^(?P[\w-]+)/delete/$', c.person_delete, name='person_delete'), 10 | ] 11 | 12 | urlpatterns = [ 13 | url(r'^$', c.home, name='home'), 14 | url(r'^person/', include(person_patterns)), 15 | ] 16 | -------------------------------------------------------------------------------- /basic/myproject/core/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import Person 3 | 4 | gender_list = [('M', 'male'), ('F', 'female')] 5 | 6 | 7 | class PersonForm(forms.ModelForm): 8 | gender = forms.ChoiceField( 9 | choices=gender_list, initial='M', widget=forms.RadioSelect) 10 | 11 | class Meta: 12 | model = Person 13 | fields = ['gender', 'treatment', 'first_name', 'last_name', 'slug', 14 | 'email', 'cpf', 'address', 'complement', 'district', 'city', 15 | 'uf', 'cep', 'birthday', 'blocked'] 16 | 17 | def clean_cpf(self): 18 | return self.cleaned_data['cpf'] or '' 19 | -------------------------------------------------------------------------------- /basic/myproject/core/lists.py: -------------------------------------------------------------------------------- 1 | GENDER_LIST = [('M', 'male'), ('F', 'female')] 2 | 3 | TREATMENT_LIST = ( 4 | ('a', 'Arq.'), 5 | ('aa', 'Arqa.'), 6 | ('d', 'Dona'), 7 | ('dr', 'Dr.'), 8 | ('dra', 'Dra.'), 9 | ('e', 'Eng.'), 10 | ('ea', u'Engª.'), 11 | ('p', 'Prof.'), 12 | ('pa', 'Profa.'), 13 | ('sr', 'Sr.'), 14 | ('sra', 'Sra.'), 15 | ('srta', 'Srta.'), 16 | ) 17 | 18 | PHONE_TYPE = ( 19 | ('pri', 'principal'), 20 | ('com', 'comercial'), 21 | ('res', 'residencial'), 22 | ('cel', 'celular'), 23 | ('cl', 'Claro'), 24 | ('oi', 'Oi'), 25 | ('t', 'Tim'), 26 | ('v', 'Vivo'), 27 | ('n', 'Nextel'), 28 | ('fax', 'fax'), 29 | ('o', 'outros'), 30 | ) 31 | -------------------------------------------------------------------------------- /basic/myproject/core/migrations/0002_auto_20161128_1711.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-28 17:11 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('core', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='person', 17 | name='cpf', 18 | field=models.CharField(blank=True, max_length=11, unique=True, verbose_name='CPF'), 19 | ), 20 | migrations.AlterField( 21 | model_name='person', 22 | name='phone', 23 | field=models.CharField(blank=True, default='', max_length=20), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /basic/myproject/selenium/gen_names.py: -------------------------------------------------------------------------------- 1 | import random 2 | import names 3 | 4 | """ List of values for use in choices in models. """ 5 | treatment_male_list = ('Arq', 'Dr', 'Eng', 'Prof', 'Sr',) 6 | 7 | treatment_female_list = ('Arqa', 'Dona', 'Engª', 'Profa', 'Sra', 'Srta',) 8 | 9 | 10 | def gen_male_first_name(): 11 | treatment = random.choice(treatment_male_list) 12 | first_name = names.get_first_name(gender='male') 13 | c = {'treatment': treatment, 'first_name': first_name} 14 | return c 15 | 16 | 17 | def gen_female_first_name(): 18 | treatment = random.choice(treatment_female_list) 19 | first_name = names.get_first_name(gender='female') 20 | c = {'treatment': treatment, 'first_name': first_name} 21 | return c 22 | 23 | 24 | def gen_last_name(): 25 | return names.get_last_name() 26 | -------------------------------------------------------------------------------- /basic/myproject/core/admin.py: -------------------------------------------------------------------------------- 1 | from daterange_filter.filter import DateRangeFilter 2 | from django.contrib import admin 3 | from .models import Person, Phone 4 | from .forms import PersonForm 5 | 6 | 7 | class PhoneInline(admin.TabularInline): 8 | model = Phone 9 | extra = 1 10 | 11 | 12 | @admin.register(Person) 13 | class PersonAdmin(admin.ModelAdmin): 14 | inlines = [PhoneInline] 15 | list_display = ('__str__', 'slug', 'gender', 'email', 'cpf', 16 | 'uf', 'birthday', 'created', 'blocked') 17 | date_hierarchy = 'created' 18 | search_fields = ('first_name', 'last_name', 'email', 'cpf') 19 | list_filter = ( 20 | 'gender', 21 | ('created', DateRangeFilter), 22 | ) 23 | form = PersonForm 24 | 25 | def phone(self, obj): 26 | return obj.phone_set.first() 27 | 28 | phone.short_description = 'phone' 29 | -------------------------------------------------------------------------------- /basic/myproject/core/templates/nav.html: -------------------------------------------------------------------------------- 1 | 2 | 22 | -------------------------------------------------------------------------------- /basic/myproject/core/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Welcome!

7 |

Contacts list make in Django.

8 |

The project contains:

9 |
    10 |
  • Core App
  • 11 |
  • Person Model
  • 12 |
  • Person List
  • 13 |
  • Person Detail
  • 14 |
  • Person Form
  • 15 |
  • Person Admin
  • 16 |
  • Tests with Selenium
  • 17 |
  • Fixtures with Generate Random Values
  • 18 |
19 | 20 | 23 | 24 |
25 |
26 | {% endblock content %} 27 | -------------------------------------------------------------------------------- /basic/myproject/core/tests/test_model_person.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from django.shortcuts import resolve_url as r 3 | from django.test import TestCase 4 | from myproject.core.models import Person 5 | from myproject.core.tests import PERSON_DATA 6 | 7 | 8 | class PersonTest(TestCase): 9 | 10 | def setUp(self): 11 | self.obj = Person.objects.create(**PERSON_DATA) 12 | 13 | def test_create(self): 14 | self.assertTrue(Person.objects.exists()) 15 | 16 | def test_created(self): 17 | ''' Person must have an auto created attr. ''' 18 | self.assertIsInstance(self.obj.created, datetime) 19 | 20 | def test_str(self): 21 | self.assertEqual('Sr. Regis Santos', str(self.obj)) 22 | 23 | def test_ordering(self): 24 | self.assertListEqual(['first_name'], Person._meta.ordering) 25 | 26 | def test_get_absolute_url(self): 27 | url = r('core:person_detail', slug=self.obj.slug) 28 | self.assertEqual(url, self.obj.get_absolute_url()) 29 | -------------------------------------------------------------------------------- /basic/myproject/core/templates/footer.html: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /basic/myproject/core/static/css/main.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer styles 2 | -------------------------------------------------- */ 3 | /* http://getbootstrap.com/examples/sticky-footer-navbar/sticky-footer-navbar.css */ 4 | /* http://getbootstrap.com/2.3.2/examples/sticky-footer.html */ 5 | html { 6 | position: relative; 7 | min-height: 100%; 8 | } 9 | body { 10 | /* Margin bottom by footer height */ 11 | margin-bottom: 50px; 12 | } 13 | #footer { 14 | position: absolute; 15 | bottom: 0; 16 | width: 100%; 17 | /* Set the fixed height of the footer here */ 18 | height: 60px; 19 | background-color: #101010; 20 | } 21 | .credit { 22 | /* Center vertical text */ 23 | margin: 20px 0; 24 | } 25 | /* Lastly, apply responsive CSS fixes as necessary */ 26 | @media (max-width: 767px) { 27 | body { 28 | margin-bottom: 120px; 29 | } 30 | 31 | #footer { 32 | height: 120px; 33 | padding-left: 5px; 34 | padding-right: 5px; 35 | } 36 | } 37 | /* My personal styles. */ 38 | .ok { 39 | color: #44AD41; /*verde*/ 40 | } 41 | 42 | .no { 43 | color: #DE2121; /*vermelho*/ 44 | } 45 | -------------------------------------------------------------------------------- /basic/myproject/core/templates/pagination.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
    5 |
  • «
  • 6 | {% if page_obj.has_previous %} 7 |
  • 8 | {% endif %} 9 |
  • {{ page_obj.number }}
  • 10 | 17 | {% if page_obj.has_next %} 18 |
  • 19 | {% endif %} 20 |
  • »
  • 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /basic/myproject/core/migrations/0004_auto_20161128_1810.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-28 18:10 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('core', '0003_auto_20161128_1801'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Phone', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('phone', models.CharField(blank=True, max_length=20)), 21 | ('phone_type', models.CharField(choices=[('pri', 'principal'), ('com', 'comercial'), ('res', 'residencial'), ('cel', 'celular'), ('cl', 'Claro'), ('oi', 'Oi'), ('t', 'Tim'), ('v', 'Vivo'), ('n', 'Nextel'), ('fax', 'fax'), ('o', 'outros')], default='pri', max_length=3)), 22 | ], 23 | ), 24 | migrations.RemoveField( 25 | model_name='person', 26 | name='phone', 27 | ), 28 | migrations.AddField( 29 | model_name='phone', 30 | name='person', 31 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Person'), 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /_test_mixer.py: -------------------------------------------------------------------------------- 1 | from mixer.backend.django import mixer 2 | from myproject.core.models import Person 3 | 4 | person = mixer.blend(Person) 5 | person.gender 6 | person.treatment 7 | person.first_name 8 | person.last_name 9 | person.cpf 10 | person.birthday 11 | person.email 12 | person.phone 13 | person.blocked 14 | 15 | mixer.blend(Person).birthday 16 | 17 | 18 | #----------------------------------------- 19 | from mixer.backend.django import mixer 20 | from myproject.core.models import Person 21 | 22 | mixer = Mixer(locale='pt_br') 23 | person = mixer.blend(Person) 24 | person.first_name 25 | person.last_name 26 | 27 | 28 | person.faker.name() 29 | # person.faker.gender() 30 | # person.faker.treatment() 31 | person.faker.first_name() 32 | person.faker.last_name() 33 | person.faker.cpf() 34 | person.faker.date_time() 35 | person.faker.iso8601() 36 | person.faker.email() 37 | person.faker.phone_number() 38 | # person.faker.blocked() 39 | 40 | #----------------------------------------- 41 | from mixer.backend.django import Mixer 42 | from myproject.core.models import Person 43 | 44 | person = Mixer(locale='pt_br') 45 | first_name = person.faker.first_name() 46 | last_name = person.faker.last_name() 47 | cpf = person.faker.cpf() 48 | birthday = person.faker.iso8601() 49 | email = person.faker.email() 50 | phone = person.faker.phone_number() 51 | 52 | mixer.blend(Person, first_name=first_name, last_name=last_name, 53 | cpf=cpf, birthday=birthday, email=email, phone=phone) 54 | -------------------------------------------------------------------------------- /basic/myproject/core/templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {% block title %}Django{% endblock title %} 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | {% include "nav.html" %} 35 | 36 |
37 |
38 | {% block content %}{% endblock content %} 39 |
40 |
41 | 42 | {% include "footer.html" %} 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /basic/myproject/core/views.py: -------------------------------------------------------------------------------- 1 | from django.core.urlresolvers import reverse_lazy as r 2 | from django.db.models import Q 3 | from django.shortcuts import render 4 | from django.views.generic import CreateView, ListView, DetailView 5 | from django.views.generic import UpdateView, DeleteView 6 | from .models import Person 7 | from .forms import PersonForm 8 | 9 | 10 | def home(request): 11 | return render(request, 'index.html') 12 | 13 | 14 | class CounterMixin(object): 15 | 16 | def get_context_data(self, **kwargs): 17 | context = super(CounterMixin, self).get_context_data(**kwargs) 18 | context['count'] = self.get_queryset().count() 19 | return context 20 | 21 | 22 | class PersonList(CounterMixin, ListView): 23 | template_name = 'core/person_list.html' 24 | model = Person 25 | context_object_name = 'persons' 26 | paginate_by = 10 27 | 28 | def get_queryset(self): 29 | persons = Person.objects.all() 30 | q = self.request.GET.get('search_box') 31 | if q is not None: 32 | persons = persons.filter( 33 | Q(first_name__icontains=q) | 34 | Q(last_name__icontains=q)) 35 | return persons 36 | 37 | 38 | class PersonCreate(CreateView): 39 | template_name = 'core/person_form.html' 40 | form_class = PersonForm 41 | success_url = r('core:person_list') 42 | 43 | 44 | person_detail = DetailView.as_view(model=Person) 45 | 46 | person_update = UpdateView.as_view(model=Person, form_class=PersonForm) 47 | 48 | person_delete = DeleteView.as_view(model=Person, 49 | success_url=r('core:person_list')) 50 | -------------------------------------------------------------------------------- /basic/myproject/core/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-28 16:52 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Person', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('created', models.DateTimeField(auto_now_add=True)), 21 | ('modified', models.DateTimeField(auto_now=True)), 22 | ('gender', models.CharField(choices=[('M', 'male'), ('F', 'female')], max_length=1)), 23 | ('treatment', models.CharField(choices=[('a', 'Arq.'), ('aa', 'Arqa.'), ('d', 'Dona'), ('dr', 'Dr.'), ('dra', 'Dra.'), ('e', 'Eng.'), ('ea', 'Engª.'), ('p', 'Prof.'), ('pa', 'Profa.'), ('sr', 'Sr.'), ('sra', 'Sra.'), ('srta', 'Srta.')], default='', max_length=4)), 24 | ('first_name', models.CharField(max_length=30, verbose_name='first name')), 25 | ('last_name', models.CharField(max_length=30, verbose_name='last name')), 26 | ('cpf', models.CharField(max_length=11, unique=True, verbose_name='CPF')), 27 | ('birthday', models.DateTimeField(blank=True, null=True)), 28 | ('email', models.EmailField(blank=True, max_length=254)), 29 | ('phone', models.CharField(default='', max_length=20)), 30 | ('blocked', models.BooleanField(default=False)), 31 | ], 32 | options={ 33 | 'verbose_name': 'contact', 34 | 'verbose_name_plural': 'contacts', 35 | 'ordering': ['first_name'], 36 | }, 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /basic/myproject/core/migrations/0003_auto_20161128_1801.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-28 18:01 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('core', '0002_auto_20161128_1711'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='person', 17 | name='address', 18 | field=models.CharField(blank=True, max_length=100), 19 | ), 20 | migrations.AddField( 21 | model_name='person', 22 | name='cep', 23 | field=models.CharField(blank=True, max_length=9, verbose_name='CEP'), 24 | ), 25 | migrations.AddField( 26 | model_name='person', 27 | name='city', 28 | field=models.CharField(blank=True, max_length=100), 29 | ), 30 | migrations.AddField( 31 | model_name='person', 32 | name='complement', 33 | field=models.CharField(blank=True, max_length=100), 34 | ), 35 | migrations.AddField( 36 | model_name='person', 37 | name='district', 38 | field=models.CharField(blank=True, max_length=100), 39 | ), 40 | migrations.AddField( 41 | model_name='person', 42 | name='uf', 43 | field=models.CharField(blank=True, choices=[('AC', 'Acre'), ('AL', 'Alagoas'), ('AP', 'Amapá'), ('AM', 'Amazonas'), ('BA', 'Bahia'), ('CE', 'Ceará'), ('DF', 'Distrito Federal'), ('ES', 'Espírito Santo'), ('GO', 'Goiás'), ('MA', 'Maranhão'), ('MT', 'Mato Grosso'), ('MS', 'Mato Grosso do Sul'), ('MG', 'Minas Gerais'), ('PA', 'Pará'), ('PB', 'Paraíba'), ('PR', 'Paraná'), ('PE', 'Pernambuco'), ('PI', 'Piauí'), ('RJ', 'Rio de Janeiro'), ('RN', 'Rio Grande do Norte'), ('RS', 'Rio Grande do Sul'), ('RO', 'Rondônia'), ('RR', 'Roraima'), ('SC', 'Santa Catarina'), ('SP', 'São Paulo'), ('SE', 'Sergipe'), ('TO', 'Tocantins')], max_length=2, verbose_name='UF'), 44 | ), 45 | ] 46 | -------------------------------------------------------------------------------- /basic/myproject/selenium/gen_random_values.py: -------------------------------------------------------------------------------- 1 | import string 2 | from random import random, randrange, choice 3 | from datetime import date, datetime, timedelta 4 | 5 | 6 | def gen_cpf(): 7 | def calcula_digito(digs): 8 | s = 0 9 | qtd = len(digs) 10 | for i in range(qtd): 11 | s += n[i] * (1 + qtd - i) 12 | res = 11 - s % 11 13 | if res >= 10: 14 | return 0 15 | return res 16 | n = [randrange(10) for i in range(9)] 17 | n.append(calcula_digito(n)) 18 | n.append(calcula_digito(n)) 19 | return "%d%d%d%d%d%d%d%d%d%d%d" % tuple(n) 20 | 21 | 22 | def gen_digits(max_length): 23 | return str(''.join(choice(string.digits) for i in range(max_length))) 24 | 25 | 26 | def gen_phone(): 27 | # gera um telefone no formato xx xxxxx-xxxx 28 | digits_ = gen_digits(11) 29 | return '{} 9{}-{}'.format(digits_[:2], digits_[3:7], digits_[7:]) 30 | 31 | 32 | def gen_date(min_year=1900, max_year=datetime.now().year): 33 | # gera um date no formato yyyy-mm-dd 34 | start = date(min_year, 1, 1) 35 | years = max_year - min_year + 1 36 | end = start + timedelta(days=365 * years) 37 | return start + (end - start) * random() 38 | 39 | 40 | def convert_date(d): 41 | # converte data no formato mês, dia, ano. 42 | return d.strftime('%m/%d/%Y') 43 | 44 | 45 | def gen_datetime(min_year=1900, max_year=datetime.now().year): 46 | # gera um datetime no formato yyyy-mm-dd hh:mm:ss.000000 47 | start = datetime(min_year, 1, 1) 48 | years = max_year - min_year + 1 49 | end = start + timedelta(days=365 * years) 50 | return (start + (end - start) * random()).isoformat(" ") 51 | 52 | 53 | def gen_timestamp(min_year=1915, max_year=datetime.now().year): 54 | # gera um datetime no formato yyyy-mm-dd hh:mm:ss.000000 55 | min_date = datetime(min_year, 1, 1) 56 | max_date = datetime(max_year + 1, 1, 1) 57 | delta = random() * (max_date - min_date).total_seconds() 58 | return (min_date + timedelta(seconds=delta)).isoformat(" ") 59 | 60 | # See more gen_random_values in 61 | # https://gist.github.com/rg3915/744aacde209046901748 62 | -------------------------------------------------------------------------------- /basic/myproject/selenium/selenium_person.py: -------------------------------------------------------------------------------- 1 | import time 2 | from random import randint 3 | from decouple import config 4 | from selenium import webdriver 5 | from gen_address import address, district, city, state_name, complement 6 | from gen_names import gen_male_first_name, gen_female_first_name, gen_last_name 7 | from gen_random_values import gen_digits, gen_cpf, gen_date, convert_date 8 | 9 | 10 | HOME = config('HOME') 11 | # page = webdriver.Firefox() 12 | page = webdriver.Chrome(executable_path=HOME + '/chromedriver/chromedriver') 13 | page.maximize_window() 14 | time.sleep(0.5) 15 | page.get('http://localhost:8000/person/add/') 16 | 17 | INDEX = randint(0, 146) 18 | 19 | g = randint(0, 1) 20 | 21 | if g: 22 | gender = 'id_gender_1' 23 | dict_ = gen_female_first_name() 24 | else: 25 | gender = 'id_gender_0' 26 | dict_ = gen_male_first_name() 27 | 28 | treatment = dict_['treatment'] 29 | first_name = dict_['first_name'] 30 | last_name = gen_last_name() 31 | print(first_name, last_name) 32 | 33 | slug = '{}-{}'.format(first_name.lower(), last_name.lower()) 34 | 35 | email = slug + '@example.com' 36 | 37 | cep = '{}-{}'.format(gen_digits(5), gen_digits(3)) 38 | 39 | complement_ = '{} {}'.format(complement(), gen_digits(2)) 40 | 41 | photo = 'http://icons.iconarchive.com/icons/icons-land/vista-people/256/Office-Customer-Male-Light-icon.png' 42 | 43 | search = page.find_element_by_id(gender) 44 | search.click() 45 | 46 | fields = [ 47 | ['id_treatment', treatment], 48 | ['id_first_name', first_name], 49 | ['id_last_name', last_name], 50 | ['id_slug', slug], 51 | ['id_email', email], 52 | ['id_cpf', gen_cpf()], 53 | ['id_address', address()], 54 | ['id_complement', complement_], 55 | ['id_district', district()], 56 | ['id_city', city()], 57 | ['id_uf', state_name()], 58 | ['id_cep', cep], 59 | ['id_birthday', convert_date(gen_date())], 60 | ] 61 | 62 | for field in fields: 63 | search = page.find_element_by_id(field[0]) 64 | search.send_keys(field[1]) 65 | time.sleep(0.2) 66 | 67 | 68 | # button = page.find_element_by_id('id_submit') 69 | button = page.find_element_by_class_name('btn-primary') 70 | # button.click() 71 | 72 | # page.quit() 73 | -------------------------------------------------------------------------------- /basic/myproject/core/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.core.urlresolvers import reverse_lazy 3 | from localflavor.br.br_states import STATE_CHOICES 4 | # List of values for use in choices 5 | from .lists import GENDER_LIST, TREATMENT_LIST, PHONE_TYPE 6 | 7 | 8 | class TimeStampedModel(models.Model): 9 | created = models.DateTimeField(auto_now_add=True, auto_now=False) 10 | modified = models.DateTimeField(auto_now_add=False, auto_now=True) 11 | 12 | class Meta: 13 | abstract = True 14 | 15 | 16 | class Address(models.Model): 17 | address = models.CharField(max_length=100, blank=True) 18 | complement = models.CharField(max_length=100, blank=True) 19 | district = models.CharField(max_length=100, blank=True) 20 | city = models.CharField(max_length=100, blank=True) 21 | uf = models.CharField('UF', max_length=2, 22 | choices=STATE_CHOICES, blank=True) 23 | cep = models.CharField('CEP', max_length=9, blank=True) 24 | 25 | class Meta: 26 | abstract = True 27 | 28 | 29 | class Person(TimeStampedModel, Address): 30 | gender = models.CharField(max_length=1, choices=GENDER_LIST) 31 | treatment = models.CharField( 32 | max_length=4, choices=TREATMENT_LIST, default='') 33 | slug = models.SlugField('slug') 34 | first_name = models.CharField('first name', max_length=30) 35 | last_name = models.CharField('last name', max_length=30) 36 | cpf = models.CharField('CPF', max_length=11, unique=True, blank=True) 37 | birthday = models.DateTimeField(null=True, blank=True) 38 | email = models.EmailField(blank=True) 39 | blocked = models.BooleanField(default=False) 40 | 41 | class Meta: 42 | ordering = ['first_name'] 43 | verbose_name = 'contact' 44 | verbose_name_plural = 'contacts' 45 | 46 | def __str__(self): 47 | fname = [self.get_treatment_display(), self.first_name, self.last_name] 48 | return ' '.join(filter(None, fname)) 49 | 50 | full_name = property(__str__) 51 | 52 | def get_absolute_url(self): 53 | ''' return slug ''' 54 | return reverse_lazy('core:person_detail', kwargs={'slug': self.slug}) 55 | 56 | 57 | class Phone(models.Model): 58 | phone = models.CharField(max_length=20, blank=True) 59 | person = models.ForeignKey('Person') 60 | phone_type = models.CharField( 61 | max_length=3, choices=PHONE_TYPE, default='pri') 62 | 63 | def __str__(self): 64 | return self.phone 65 | -------------------------------------------------------------------------------- /basic/myproject/fixtures/shell_person.py: -------------------------------------------------------------------------------- 1 | import random 2 | import names 3 | from myproject.core.models import Person, Phone 4 | from myproject.selenium.gen_address import address, district, city, state_uf, complement 5 | from myproject.selenium.gen_names import gen_male_first_name, gen_female_first_name, gen_last_name 6 | from myproject.selenium.gen_random_values import gen_digits, gen_cpf, gen_timestamp, gen_phone 7 | 8 | 9 | PHONE_TYPE = ('pri', 'com', 'res', 'cel') 10 | person_list = [] 11 | phone_list = [] 12 | REPEAT = 20 13 | 14 | 15 | def person_data(): 16 | gender = random.choice(['M', 'F']) 17 | if gender == 'M': 18 | treatment = gen_male_first_name()['treatment'] 19 | first_name = gen_male_first_name()['first_name'] 20 | else: 21 | treatment = gen_female_first_name()['treatment'] 22 | first_name = gen_female_first_name()['first_name'] 23 | last_name = names.get_last_name() 24 | slug = '{}-{}'.format(first_name.lower(), last_name.lower()) 25 | email = slug + '@example.com' 26 | birthday = gen_timestamp() + '+00' 27 | blocked = random.choice([1, 0]) 28 | cep = '{}-{}'.format(gen_digits(5), gen_digits(3)) 29 | complement_ = '{} {}'.format(complement(), gen_digits(2)) 30 | return {'gender': gender, 31 | 'treatment': treatment, 32 | 'first_name': first_name, 33 | 'last_name': last_name, 34 | 'slug': slug, 35 | 'cpf': gen_cpf(), 36 | 'birthday': birthday, 37 | 'email': email, 38 | 'address': address(), 39 | 'complement': complement_, 40 | 'district': district(), 41 | 'city': city(), 42 | 'uf': state_uf(), 43 | 'cep': cep, 44 | 'blocked': blocked, 45 | } 46 | 47 | 48 | # Appending person_list 49 | for _ in range(REPEAT): 50 | person_list.append(person_data()) 51 | 52 | # Insert Persons 53 | obj = [Person(**person) for person in person_list] 54 | Person.objects.bulk_create(obj) 55 | 56 | # Appending phone_list 57 | persons = Person.objects.all() 58 | for person in persons: 59 | for _ in range(1, random.randint(2, 5)): 60 | phone_list.append({ 61 | 'person': person, 62 | 'phone': gen_phone(), 63 | 'phone_type': random.choice(PHONE_TYPE), 64 | }) 65 | 66 | # Insert Phones 67 | obj = [Phone(**phone) for phone in phone_list] 68 | Phone.objects.bulk_create(obj) 69 | 70 | print('\n%d Persons salvo com sucesso.' % REPEAT) 71 | -------------------------------------------------------------------------------- /basic/myproject/core/templates/core/person_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Contacts{% endblock title %} 4 | 5 | {% block content %} 6 | 7 | 20 | 21 |

Contacts List

22 | 23 | {% if persons %} 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {% for person in persons %} 37 | {% if person.blocked %} 38 | 39 | {% else %} 40 | 41 | {% endif %} 42 | 43 | 44 | {% if person.phone_set.first %} 45 | 50 | {% else %} 51 | 52 | {% endif %} 53 | 54 | 55 | {% if person.blocked %} 56 | 57 | {% else %} 58 | 59 | {% endif %} 60 | 61 | {% endfor %} 62 | 63 |
NameEmailPhoneCPFBirthdayBlocked
{{ person.full_name }}{{ person.email }}{{ person.phone_set.first }} 46 | {% if person.phone_set.count > 1 %} 47 | +{{ person.phone_set.count|add:"-1" }} 48 | {% endif %} 49 | ---{{ person.cpf }}{{ person.birthday|date:"d/m/Y" }}
64 | {% else %} 65 |
66 |

Without items in this list.

67 | 68 | 69 | 72 | 73 |
74 | {% endif %} 75 | 76 |
77 | {% if count > 0 %} 78 |
79 |

{{ persons|length }} contact{{ persons|length|pluralize }}

80 |

Total: {{ page_obj.paginator.count }} contact{{ page_obj.paginator.count|pluralize }}

81 | {% endif %} 82 |
83 | 84 | 85 | {% if count > 0 %} 86 | {% include "pagination.html" %} 87 | {% endif %} 88 | 89 | {% endblock content %} 90 | -------------------------------------------------------------------------------- /basic/myproject/core/static/css/social.css: -------------------------------------------------------------------------------- 1 | /* http://www.kodingmadesimple.com/2014/11/create-stylish-bootstrap-3-social-media-icons.html */ 2 | .social { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | .social ul { 8 | margin: 0; 9 | padding: 5px; 10 | } 11 | 12 | .social ul li { 13 | margin: 5px; 14 | list-style: none outside none; 15 | display: inline-block; 16 | } 17 | 18 | .social i { 19 | width: 40px; 20 | height: 40px; 21 | color: #FFF; 22 | background-color: #909AA0; 23 | font-size: 22px; 24 | text-align:center; 25 | padding-top: 12px; 26 | border-radius: 50%; 27 | -moz-border-radius: 50%; 28 | -webkit-border-radius: 50%; 29 | -o-border-radius: 50%; 30 | transition: all ease 0.3s; 31 | -moz-transition: all ease 0.3s; 32 | -webkit-transition: all ease 0.3s; 33 | -o-transition: all ease 0.3s; 34 | -ms-transition: all ease 0.3s; 35 | text-decoration: none; 36 | } 37 | 38 | .social .fa-facebook { 39 | background: #4060A5; 40 | } 41 | 42 | .social .fa-twitter { 43 | background: #00ABE3; 44 | } 45 | 46 | .social .fa-google-plus { 47 | background: #e64522; 48 | } 49 | 50 | .social .fa-github { 51 | background: #343434; 52 | } 53 | 54 | .social .fa-pinterest { 55 | background: #cb2027; 56 | } 57 | 58 | .social .fa-linkedin { 59 | background: #0094BC; 60 | } 61 | 62 | .social .fa-flickr { 63 | background: #FF57AE; 64 | } 65 | 66 | .social .fa-instagram { 67 | background: #375989; 68 | } 69 | 70 | .social .fa-vimeo-square { 71 | background: #83DAEB; 72 | } 73 | 74 | .social .fa-stack-overflow { 75 | background: #FEA501; 76 | } 77 | 78 | .social .fa-dropbox { 79 | background: #017FE5; 80 | } 81 | 82 | .social .fa-tumblr { 83 | background: #3a5876; 84 | } 85 | 86 | .social .fa-dribbble { 87 | background: #F46899; 88 | } 89 | 90 | .social .fa-skype { 91 | background: #00C6FF; 92 | } 93 | 94 | .social .fa-stack-exchange { 95 | background: #4D86C9; 96 | } 97 | 98 | .social .fa-youtube { 99 | background: #FF1F25; 100 | } 101 | 102 | .social .fa-xing { 103 | background: #005C5E; 104 | } 105 | 106 | .social .fa-rss { 107 | background: #e88845; 108 | } 109 | 110 | .social .fa-foursquare { 111 | background: #09B9E0; 112 | } 113 | 114 | .social .fa-youtube-play { 115 | background: #DF192A; 116 | } 117 | 118 | .social .fa-telegram { 119 | background: #0088cc; 120 | } 121 | 122 | .social .fa-slack { 123 | background: #4F3A4B; 124 | } 125 | 126 | .social .fa-whatsapp { 127 | background: #65BC54; 128 | } 129 | 130 | .socialfooter { 131 | margin: 0; 132 | padding: 0; 133 | } 134 | 135 | .socialfooter ul { 136 | margin: 0; 137 | padding: 5px; 138 | } 139 | 140 | .socialfooter ul li { 141 | margin: 5px; 142 | list-style: none outside none; 143 | display: inline-block; 144 | } 145 | 146 | .socialfooter i { 147 | color: #FFF; 148 | font-size: 22px; 149 | text-align:center; 150 | padding-top: 12px; 151 | border-radius: 50%; 152 | -moz-border-radius: 50%; 153 | -webkit-border-radius: 50%; 154 | -o-border-radius: 50%; 155 | transition: all ease 0.3s; 156 | -moz-transition: all ease 0.3s; 157 | -webkit-transition: all ease 0.3s; 158 | -o-transition: all ease 0.3s; 159 | -ms-transition: all ease 0.3s; 160 | text-decoration: none; 161 | } 162 | 163 | .socialfooter i:hover { 164 | color: #00ABE3; 165 | } 166 | -------------------------------------------------------------------------------- /basic/myproject/selenium/gen_address.py: -------------------------------------------------------------------------------- 1 | import names 2 | from random import choice, randint 3 | 4 | 5 | street_prefixes = ('Alameda', 'Avenida', 'Estrada', 6 | 'Largo', 'Praça', 'Rua', 'Travessa') 7 | 8 | 9 | districts = ('Acaiaca', 'Aguas Claras', 'Alpes', 'Alto Barroca', 10 | 'Alto Dos Pinheiros', 'Alto Vera Cruz', 'Anchieta', 'Bacurau', 11 | 'Bandeirantes', 'Barreiro', 'Barroca', 'Belmonte', 'Bonfim', 12 | 'Bonsucesso', 'Cachoeirinha', 'Caiçaras', 'Califórnia', 13 | 'Diamante', 'Dom Joaquim', 'Embaúbas', 'Esplanada', 'Estrela', 14 | 'Floramar', 'Floresta', 'Garças', 'Glória', 'Grajaú', 15 | 'Horto Florestal', 'Indaiá', 'Ipe', 'Ipiranga', 'Itaipu', 16 | 'Jaraguá', 'Jardim Alvorada', 'Jardinópolis', 'Jatobá', 17 | 'Lagoa', 'Laranjeiras', 'Liberdade', 'Madri', 'Manacas', 18 | 'Miramar', 'Nova America', 'Novo Tupi', 'Oeste', 'Pantanal', 19 | 'Renascença', 'Santa Inês', 'Santa Sofia', 'Teixeira Dias', 20 | 'Tiradentes', 'Urca', 'Vera Cruz', 'Vila Da Luz', 'Vila Pilar', 21 | 'Vitoria', 'Xangri-Lá', 'Zilah Sposito', ) 22 | 23 | states = ( 24 | ('AC', 'Acre'), 25 | ('AL', 'Alagoas'), 26 | ('AP', 'Amapá'), 27 | ('AM', 'Amazonas'), 28 | ('BA', 'Bahia'), 29 | ('CE', 'Ceará'), 30 | ('DF', 'Distrito Federal'), 31 | ('ES', 'Espírito Santo'), 32 | ('GO', 'Goiás'), 33 | ('MA', 'Maranhão'), 34 | ('MT', 'Mato Grosso'), 35 | ('MS', 'Mato Grosso do Sul'), 36 | ('MG', 'Minas Gerais'), 37 | ('PA', 'Pará'), 38 | ('PB', 'Paraíba'), 39 | ('PR', 'Paraná'), 40 | ('PE', 'Pernambuco'), 41 | ('PI', 'Piauí'), 42 | ('RJ', 'Rio de Janeiro'), 43 | ('RN', 'Rio Grande do Norte'), 44 | ('RS', 'Rio Grande do Sul'), 45 | ('RO', 'Rondônia'), 46 | ('RR', 'Roraima'), 47 | ('SC', 'Santa Catarina'), 48 | ('SP', 'São Paulo'), 49 | ('SE', 'Sergipe'), 50 | ('TO', 'Tocantins')) 51 | 52 | 53 | complements = ('andar', 'apto', 'casa', 'fundos', 'loja') 54 | 55 | 56 | def random_element(elements): 57 | return choice(elements) 58 | 59 | 60 | def gen_first_name(): 61 | return names.get_first_name() 62 | 63 | 64 | def gen_last_name(): 65 | return names.get_last_name() 66 | 67 | 68 | def address(): 69 | """ 70 | :example 'Rua Eurides da Cunha, 116' 71 | """ 72 | street_prefix = random_element(street_prefixes) 73 | first_name = gen_first_name() 74 | last_name = gen_last_name() 75 | gen_number = randint(1, 9999) 76 | pattern = '{} {} {}, {}'.format( 77 | street_prefix, first_name, last_name, gen_number) 78 | return pattern 79 | 80 | 81 | def city(): 82 | return gen_last_name() 83 | 84 | 85 | def state(): 86 | """ 87 | Randomly returns a Brazilian State ('sigla' , 'nome'). 88 | :example ('MG' . 'Minas Gerais') 89 | """ 90 | return random_element(states) 91 | 92 | 93 | def state_name(): 94 | """ 95 | Randomly returns a Brazilian State Name 96 | :example 'Minas Gerais' 97 | """ 98 | return state()[1] 99 | 100 | 101 | def state_uf(): 102 | """ 103 | Randomly returns the abbreviation of a Brazilian State 104 | :example 'MG' 105 | """ 106 | return state()[0] 107 | 108 | 109 | def district(): 110 | """ 111 | Randomly returns a bairro (neighborhood) name. The names were taken from the city of Belo Horizonte - Minas Gerais 112 | :example 'Serra' 113 | """ 114 | return random_element(districts) 115 | 116 | # https://github.com/joke2k/faker/blob/master/faker/providers/__init__.py 117 | 118 | 119 | def complement(): 120 | return random_element(complements) 121 | -------------------------------------------------------------------------------- /basic/myproject/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for myproject project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.9. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.9/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'tsu--1ww)gv#_%24sqjxdvdu^u52-#ii($0+s!v76647gq6^v5' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | # third-party apps 41 | 'bootstrapform', 42 | 'daterange_filter', 43 | # my app 44 | 'myproject.core', 45 | ] 46 | 47 | MIDDLEWARE_CLASSES = [ 48 | 'django.middleware.security.SecurityMiddleware', 49 | 'django.contrib.sessions.middleware.SessionMiddleware', 50 | 'django.middleware.common.CommonMiddleware', 51 | 'django.middleware.csrf.CsrfViewMiddleware', 52 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 53 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 54 | 'django.contrib.messages.middleware.MessageMiddleware', 55 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 56 | ] 57 | 58 | ROOT_URLCONF = 'myproject.urls' 59 | 60 | TEMPLATES = [ 61 | { 62 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 63 | 'DIRS': [], 64 | 'APP_DIRS': True, 65 | 'OPTIONS': { 66 | 'context_processors': [ 67 | 'django.template.context_processors.debug', 68 | 'django.template.context_processors.request', 69 | 'django.contrib.auth.context_processors.auth', 70 | 'django.contrib.messages.context_processors.messages', 71 | ], 72 | }, 73 | }, 74 | ] 75 | 76 | WSGI_APPLICATION = 'myproject.wsgi.application' 77 | 78 | 79 | # Database 80 | # https://docs.djangoproject.com/en/1.9/ref/settings/#databases 81 | 82 | DATABASES = { 83 | 'default': { 84 | 'ENGINE': 'django.db.backends.sqlite3', 85 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 86 | } 87 | } 88 | 89 | 90 | # Password validation 91 | # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators 92 | 93 | AUTH_PASSWORD_VALIDATORS = [ 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 102 | }, 103 | { 104 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 105 | }, 106 | ] 107 | 108 | 109 | # Internationalization 110 | # https://docs.djangoproject.com/en/1.9/topics/i18n/ 111 | 112 | LANGUAGE_CODE = 'en-us' 113 | 114 | TIME_ZONE = 'UTC' 115 | 116 | USE_I18N = True 117 | 118 | USE_L10N = True 119 | 120 | USE_TZ = True 121 | 122 | 123 | # Static files (CSS, JavaScript, Images) 124 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 125 | 126 | STATIC_URL = '/static/' 127 | -------------------------------------------------------------------------------- /basic/myproject/core/templates/core/person_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load static %} 4 | 5 | {% block title %}Person Detail{% endblock title %} 6 | 7 | {% block content %} 8 | 9 | 14 | 15 |
16 |
17 | 18 |
19 |
20 |

{{ object.full_name }}

21 | {% if object.email %} 22 |

{{ object.email }}

23 | {% endif %} 24 | 38 |
39 | 40 |
41 | 42 | 43 | 44 | {% if object.phone_set.all %} 45 | {% for phone in object.phone_set.all %} 46 | 47 | 48 | 49 | 50 | {% endfor %} 51 | {% else %} 52 | 53 | 54 | 55 | 56 | {% endif %} 57 | 58 | {% if object.address %} 59 | 60 | 61 | 65 | 66 | 67 | 68 | 73 | 74 | {% endif %} 75 | {% if object.cpf %} 76 | 77 | 78 | 79 | 80 | {% endif %} 81 | {% if object.birthday %} 82 | 83 | 84 | 85 | 86 | {% endif %} 87 | 88 | 89 | 90 | 91 | 92 | 93 |
{{ phone.phone }} {{ phone.get_phone_type_display }}
---
{{ object.address }} 62 | {% if object.complement %} - {{ object.complement }}{% endif %} 63 | {% if object.district %} - {{ object.district }}{% endif %} 64 |
69 | {% if object.city %}{{ object.city }}{% endif %} 70 | {% if object.uf %} - {{ object.uf }}{% endif %} 71 | {% if object.cep %} - {{ object.cep }}{% endif %} 72 |
CPF{{ object.cpf }}
Birthday{{ object.birthday|date:"d/m/Y" }}
Blocked
94 | 95 | 96 | 99 | 100 | 101 | 104 |
105 | 106 | 107 | 127 | 128 | {% endblock content %} -------------------------------------------------------------------------------- /basic.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Create requirements 4 | mkdir requirements 5 | touch requirements.txt 6 | touch requirements/{base,dev,prod}.txt 7 | 8 | # Bootstrap templates 9 | mkdir -p myproject/core/templates/core 10 | touch myproject/core/templates/{base,index,nav,pagination}.html 11 | touch myproject/core/templates/core/person_{detail,form,list}.html 12 | 13 | echo "${green}>>> Creating static/css directory${reset}" 14 | mkdir -p myproject/core/static/css 15 | 16 | echo "${green}>>> Creating main.css${reset}" 17 | cat << EOF > myproject/core/static/css/main.css 18 | /* Sticky footer styles 19 | -------------------------------------------------- */ 20 | /* http://getbootstrap.com/examples/sticky-footer-navbar/sticky-footer-navbar.css */ 21 | /* http://getbootstrap.com/2.3.2/examples/sticky-footer.html */ 22 | html { 23 | position: relative; 24 | min-height: 100%; 25 | } 26 | body { 27 | /* Margin bottom by footer height */ 28 | margin-bottom: 60px; 29 | } 30 | #footer { 31 | position: absolute; 32 | bottom: 0; 33 | width: 100%; 34 | /* Set the fixed height of the footer here */ 35 | height: 60px; 36 | background-color: #101010; 37 | } 38 | .credit { 39 | /* Center vertical text */ 40 | margin: 20px 0; 41 | } 42 | /* Lastly, apply responsive CSS fixes as necessary */ 43 | @media (max-width: 767px) { 44 | body { 45 | margin-bottom: 120px; 46 | } 47 | 48 | #footer { 49 | height: 120px; 50 | padding-left: 5px; 51 | padding-right: 5px; 52 | } 53 | } 54 | /* My personal styles. */ 55 | .ok { 56 | color: #44AD41; /*verde*/ 57 | } 58 | 59 | .no { 60 | color: #DE2121; /*vermelho*/ 61 | } 62 | EOF 63 | 64 | echo "${green}>>> Creating social.css${reset}" 65 | cat << EOF > myproject/core/static/css/social.css 66 | /* http://www.kodingmadesimple.com/2014/11/create-stylish-bootstrap-3-social-media-icons.html */ 67 | .social { 68 | margin: 0; 69 | padding: 0; 70 | } 71 | 72 | .social ul { 73 | margin: 0; 74 | padding: 5px; 75 | } 76 | 77 | .social ul li { 78 | margin: 5px; 79 | list-style: none outside none; 80 | display: inline-block; 81 | } 82 | 83 | .social i { 84 | width: 40px; 85 | height: 40px; 86 | color: #FFF; 87 | background-color: #909AA0; 88 | font-size: 22px; 89 | text-align:center; 90 | padding-top: 12px; 91 | border-radius: 50%; 92 | -moz-border-radius: 50%; 93 | -webkit-border-radius: 50%; 94 | -o-border-radius: 50%; 95 | transition: all ease 0.3s; 96 | -moz-transition: all ease 0.3s; 97 | -webkit-transition: all ease 0.3s; 98 | -o-transition: all ease 0.3s; 99 | -ms-transition: all ease 0.3s; 100 | text-decoration: none; 101 | } 102 | 103 | .social .fa-facebook { 104 | background: #4060A5; 105 | } 106 | 107 | .social .fa-twitter { 108 | background: #00ABE3; 109 | } 110 | 111 | .social .fa-google-plus { 112 | background: #e64522; 113 | } 114 | 115 | .social .fa-github { 116 | background: #343434; 117 | } 118 | 119 | .social .fa-pinterest { 120 | background: #cb2027; 121 | } 122 | 123 | .social .fa-linkedin { 124 | background: #0094BC; 125 | } 126 | 127 | .social .fa-flickr { 128 | background: #FF57AE; 129 | } 130 | 131 | .social .fa-instagram { 132 | background: #375989; 133 | } 134 | 135 | .social .fa-vimeo-square { 136 | background: #83DAEB; 137 | } 138 | 139 | .social .fa-stack-overflow { 140 | background: #FEA501; 141 | } 142 | 143 | .social .fa-dropbox { 144 | background: #017FE5; 145 | } 146 | 147 | .social .fa-tumblr { 148 | background: #3a5876; 149 | } 150 | 151 | .social .fa-dribbble { 152 | background: #F46899; 153 | } 154 | 155 | .social .fa-skype { 156 | background: #00C6FF; 157 | } 158 | 159 | .social .fa-stack-exchange { 160 | background: #4D86C9; 161 | } 162 | 163 | .social .fa-youtube { 164 | background: #FF1F25; 165 | } 166 | 167 | .social .fa-xing { 168 | background: #005C5E; 169 | } 170 | 171 | .social .fa-rss { 172 | background: #e88845; 173 | } 174 | 175 | .social .fa-foursquare { 176 | background: #09B9E0; 177 | } 178 | 179 | .social .fa-youtube-play { 180 | background: #DF192A; 181 | } 182 | 183 | .social .fa-slack { 184 | background: #4F3A4B; 185 | } 186 | 187 | .social .fa-whatsapp { 188 | background: #65BC54; 189 | } 190 | 191 | .socialfooter { 192 | margin: 0; 193 | padding: 0; 194 | } 195 | 196 | .socialfooter ul { 197 | margin: 0; 198 | padding: 5px; 199 | } 200 | 201 | .socialfooter ul li { 202 | margin: 5px; 203 | list-style: none outside none; 204 | display: inline-block; 205 | } 206 | 207 | .socialfooter i { 208 | color: #FFF; 209 | font-size: 22px; 210 | text-align:center; 211 | padding-top: 12px; 212 | border-radius: 50%; 213 | -moz-border-radius: 50%; 214 | -webkit-border-radius: 50%; 215 | -o-border-radius: 50%; 216 | transition: all ease 0.3s; 217 | -moz-transition: all ease 0.3s; 218 | -webkit-transition: all ease 0.3s; 219 | -o-transition: all ease 0.3s; 220 | -ms-transition: all ease 0.3s; 221 | text-decoration: none; 222 | } 223 | 224 | .socialfooter i:hover { 225 | color: #00ABE3; 226 | } 227 | EOF 228 | 229 | 230 | pip install django dj-database-url django-bootstrap-form django-daterange-filter django-localflavor django-widget-tweaks python-decouple pytz selenium django-extensions 231 | 232 | python manage.py makemigrations core 233 | python manage.py migrate 234 | 235 | # Tem que copiar os arquivos 236 | cp fixtures/gen_address.py selenium/gen_address_.py 237 | cp fixtures/gen_names.py selenium/gen_names_.py 238 | cp fixtures/gen_random_values.py selenium/gen_random_values_.py 239 | -------------------------------------------------------------------------------- /minimal.sh: -------------------------------------------------------------------------------- 1 | # minimal 2 | # Shell script to create a minimal Django project. 3 | # This project require Python3. 4 | 5 | # Download: 6 | # wget --output-document=minimal.sh 7 | 8 | # Usage: 9 | # Type the following command, you can change the project name. 10 | 11 | # source minimal.sh 12 | 13 | # Colors 14 | red=`tput setaf 1` 15 | green=`tput setaf 2` 16 | reset=`tput sgr0` 17 | 18 | # default name project 19 | echo "Type the name of project (default: myproject): " 20 | echo "Digite o nome do projeto (default: myproject): " 21 | read p 22 | PROJECT=${p:-myproject} 23 | 24 | echo "${green}>>> Creating virtualenv${reset}" 25 | python -m venv .venv 26 | echo "${green}>>> .venv is created${reset}" 27 | 28 | # active 29 | sleep 2 30 | echo "${green}>>> activate the .venv${reset}" 31 | source .venv/bin/activate 32 | # shortcut prompt, optional 33 | PS1="(`basename \"$VIRTUAL_ENV\"`)\e[1;34m:/\W\e[00m$ " 34 | sleep 2 35 | 36 | # installdjango 37 | echo "${green}>>> Installing the Django${reset}" 38 | pip install -U pip 39 | pip install django dj-database-url python-decouple django-extensions 40 | pip freeze > requirements.txt 41 | 42 | # Create contrib/secret_gen.py 43 | echo "${green}>>> Creating the contrib/secret_gen.py${reset}" 44 | mkdir -p contrib 45 | cat << EOF > contrib/secret_gen.py 46 | #!/usr/bin/env python 47 | 48 | """ 49 | Django SECRET_KEY generator. 50 | """ 51 | from django.utils.crypto import get_random_string 52 | 53 | 54 | chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' 55 | 56 | CONFIG_STRING = """ 57 | DEBUG=True 58 | SECRET_KEY=%s 59 | ALLOWED_HOSTS=127.0.0.1, .localhost 60 | #DATABASE_URL=postgres://USER:PASSWORD@HOST:PORT/NAME 61 | #DEFAULT_FROM_EMAIL= 62 | #EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend 63 | #EMAIL_HOST= 64 | #EMAIL_PORT= 65 | #EMAIL_USE_TLS= 66 | #EMAIL_HOST_USER= 67 | #EMAIL_HOST_PASSWORD= 68 | """.strip() % get_random_string(50, chars) 69 | 70 | # Writing our configuration file to '.env' 71 | with open('.env', 'w') as configfile: 72 | configfile.write(CONFIG_STRING) 73 | EOF 74 | 75 | echo "${green}>>> Generate .env${reset}" 76 | python contrib/secret_gen.py 77 | 78 | echo "${green}>>> Creating .gitignore${reset}" 79 | cat << EOF > .gitignore 80 | __pycache__/ 81 | *.py[cod] 82 | *.sqlite3 83 | *.env 84 | *.DS_Store 85 | .venv/ 86 | staticfiles/ 87 | .ipynb_checkpoints/ 88 | EOF 89 | 90 | # Create Project 91 | echo "${green}>>> Creating the project '$PROJECT' ...${reset}" 92 | django-admin.py startproject $PROJECT . 93 | cd $PROJECT 94 | # Create App 95 | echo "${green}>>> Creating the app 'core' ...${reset}" 96 | python ../manage.py startapp core 97 | 98 | # up one level 99 | cd .. 100 | 101 | # ********** Editing .env and settings.py ********** 102 | # echo "${green}>>> Refactor .env${reset}" 103 | # find SECRET_KEY 104 | # grep "SECRET_KEY" $PROJECT/settings.py > .env 105 | # replace = 106 | # sed -i "s/ = /=/g" .env 107 | # replace ' 108 | # sed -i "s/'//g" .env 109 | # cat << EOF >> .env 110 | # DEBUG=True 111 | # ALLOWED_HOSTS=127.0.0.1, .localhost, .herokuapp.com 112 | # EOF 113 | 114 | echo "${green}>>> Editing settings.py${reset}" 115 | # insert text in line below of string 116 | sed -i "/import os/a\from decouple import config, Csv\nfrom dj_database_url import parse as dburl" $PROJECT/settings.py 117 | # remove everything except the 1st n characters in every line - See more at: http://www.theunixschool.com/2014/08/sed-examples-remove-delete-chars-from-line-file.html#sthash.h7FUerys.dpuf 118 | sed -i "/SECRET_KEY/d" $PROJECT/settings.py 119 | # insert text in line below of string 120 | sed -i "/keep the secret/a\SECRET_KEY = config('SECRET_KEY')" $PROJECT/settings.py 121 | # replace text 122 | sed -i "s/DEBUG = True/DEBUG = config('DEBUG', default=False, cast=bool)/g" $PROJECT/settings.py 123 | sed -i "s/ALLOWED_HOSTS\ =\ \[\]/ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv())/g" $PROJECT/settings.py 124 | # insert text in line below of string 125 | sed -i "/django.contrib.staticfiles/a\ # thirty apps\n 'django_extensions',\n \# my apps\n '$PROJECT.core'," $PROJECT/settings.py 126 | # exclude lines 127 | sed -i "/DATABASES/d" $PROJECT/settings.py 128 | sed -i "/'default':/d" $PROJECT/settings.py 129 | sed -i "/ENGINE/d" $PROJECT/settings.py 130 | # exclude 3 lines 131 | sed -i "/db.sqlite3/,+3d" $PROJECT/settings.py 132 | # insert text after 'databases' 133 | sed -i "/databases/a default_dburl = 'sqlite:///' + os.path.join(BASE_DIR, 'db.sqlite3')\nDATABASES = {\n 'default': config('DATABASE_URL', default=default_dburl, cast=dburl),\n}" $PROJECT/settings.py 134 | # replace text 135 | sed -i "s/en-us/pt-br/g" $PROJECT/settings.py 136 | # replace text 137 | sed -i "s/UTC/America\/Sao_Paulo/g" $PROJECT/settings.py 138 | # insert text in line below of string 139 | sed -i "/USE_TZ/a\\\nUSE_THOUSAND_SEPARATOR = True\n\nDECIMAL_SEPARATOR = ','" $PROJECT/settings.py 140 | sed -i "/STATIC_URL/a\STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')\n\nLOGIN_URL = '/admin/login/'" $PROJECT/settings.py 141 | 142 | # Create HttpResponse 143 | cat << EOF > $PROJECT/core/views.py 144 | from django.shortcuts import render 145 | from django.http import HttpResponse 146 | 147 | 148 | def home(request): 149 | return HttpResponse('Hello World') 150 | EOF 151 | 152 | # Create core/urls.py 153 | cat << EOF > $PROJECT/core/urls.py 154 | from django.conf.urls import url 155 | from $PROJECT.core import views as c 156 | 157 | urlpatterns = [ 158 | url(r'^$', c.home, name='home'), 159 | ] 160 | EOF 161 | 162 | # Editing urls.py 163 | cat << EOF > $PROJECT/urls.py 164 | from django.conf.urls import include, url 165 | from django.contrib import admin 166 | 167 | urlpatterns = [ 168 | url(r'', include('$PROJECT.core.urls', namespace='core')), 169 | url(r'^admin/', admin.site.urls), 170 | ] 171 | EOF 172 | 173 | # Running migrate 174 | echo "${green}>>> Running migrate ...${reset}" 175 | python manage.py migrate 176 | 177 | # Running tests 178 | echo "${green}>>> Running tests ...${reset}" 179 | python manage.py test 180 | 181 | echo "${green}>>> Creating Makefile${reset}" 182 | cat << EOF > Makefile 183 | install: 184 | tabpip install -r requirements.txt 185 | 186 | createuser: 187 | tab./manage.py createsuperuser --username='admin' --email='' 188 | 189 | clear: 190 | tabrm -rf myproject 191 | tabrm -rf __pycache__ 192 | tabrm -f db.sqlite3 193 | tabrm -f .env 194 | tabrm -f manage.py 195 | tabrm -f requirements.txt 196 | EOF 197 | 198 | # Replace tab to \t 199 | sed -i "s/tab/\t/g" Makefile 200 | 201 | echo "${green}>>> See the Makefile${reset}" 202 | cat Makefile 203 | 204 | echo "${red}>>> Important: Dont add .env in your public repository.${reset}" 205 | echo "${red}>>> KEEP YOUR SECRET_KEY AND PASSWORDS IN SECRET!!!\n${reset}" 206 | echo "${green}>>> Done${reset}" 207 | -------------------------------------------------------------------------------- /basic/fixtures.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "contenttypes.contenttype", 4 | "pk": 1, 5 | "fields": { 6 | "app_label": "admin", 7 | "model": "logentry" 8 | } 9 | }, 10 | { 11 | "model": "contenttypes.contenttype", 12 | "pk": 2, 13 | "fields": { 14 | "app_label": "auth", 15 | "model": "permission" 16 | } 17 | }, 18 | { 19 | "model": "contenttypes.contenttype", 20 | "pk": 3, 21 | "fields": { 22 | "app_label": "auth", 23 | "model": "group" 24 | } 25 | }, 26 | { 27 | "model": "contenttypes.contenttype", 28 | "pk": 4, 29 | "fields": { 30 | "app_label": "auth", 31 | "model": "user" 32 | } 33 | }, 34 | { 35 | "model": "contenttypes.contenttype", 36 | "pk": 5, 37 | "fields": { 38 | "app_label": "contenttypes", 39 | "model": "contenttype" 40 | } 41 | }, 42 | { 43 | "model": "contenttypes.contenttype", 44 | "pk": 6, 45 | "fields": { 46 | "app_label": "sessions", 47 | "model": "session" 48 | } 49 | }, 50 | { 51 | "model": "contenttypes.contenttype", 52 | "pk": 7, 53 | "fields": { 54 | "app_label": "core", 55 | "model": "person" 56 | } 57 | }, 58 | { 59 | "model": "core.person", 60 | "pk": 1, 61 | "fields": { 62 | "created": "2016-01-05T03:15:38.946Z", 63 | "modified": "2016-01-05T03:15:38.946Z", 64 | "gender": "M", 65 | "treatment": "e", 66 | "first_name": "Jesse", 67 | "last_name": "Goforth", 68 | "cpf": "82741529862", 69 | "birthday": "1995-07-13T19:47:20.342Z", 70 | "email": "j.goforth@example.com", 71 | "phone": "(43) 5173-6513", 72 | "blocked": false 73 | } 74 | }, 75 | { 76 | "model": "core.person", 77 | "pk": 2, 78 | "fields": { 79 | "created": "2016-01-05T03:15:39.116Z", 80 | "modified": "2016-01-05T03:15:39.116Z", 81 | "gender": "M", 82 | "treatment": "p", 83 | "first_name": "Johnny", 84 | "last_name": "Goyette", 85 | "cpf": "68718761539", 86 | "birthday": "1925-03-22T18:51:55.440Z", 87 | "email": "j.goyette@example.com", 88 | "phone": "(93) 0650-7803", 89 | "blocked": false 90 | } 91 | }, 92 | { 93 | "model": "core.person", 94 | "pk": 3, 95 | "fields": { 96 | "created": "2016-01-05T03:15:39.289Z", 97 | "modified": "2016-01-05T03:15:39.289Z", 98 | "gender": "M", 99 | "treatment": "e", 100 | "first_name": "William", 101 | "last_name": "Stafford", 102 | "cpf": "91105938543", 103 | "birthday": "1991-06-12T12:19:11.052Z", 104 | "email": "w.stafford@example.com", 105 | "phone": "(44) 8731-2792", 106 | "blocked": false 107 | } 108 | }, 109 | { 110 | "model": "core.person", 111 | "pk": 4, 112 | "fields": { 113 | "created": "2016-01-05T03:15:39.432Z", 114 | "modified": "2016-01-05T03:15:39.432Z", 115 | "gender": "F", 116 | "treatment": "d", 117 | "first_name": "Yolanda", 118 | "last_name": "Green", 119 | "cpf": "09133449044", 120 | "birthday": "1940-09-13T11:41:44.491Z", 121 | "email": "y.green@example.com", 122 | "phone": "(66) 3799-4812", 123 | "blocked": false 124 | } 125 | }, 126 | { 127 | "model": "core.person", 128 | "pk": 5, 129 | "fields": { 130 | "created": "2016-01-05T03:15:39.591Z", 131 | "modified": "2016-01-05T03:15:39.591Z", 132 | "gender": "M", 133 | "treatment": "sr", 134 | "first_name": "Robert", 135 | "last_name": "Bissell", 136 | "cpf": "17626244583", 137 | "birthday": "1994-11-17T09:39:12.227Z", 138 | "email": "r.bissell@example.com", 139 | "phone": "(44) 9207-2780", 140 | "blocked": false 141 | } 142 | }, 143 | { 144 | "model": "core.person", 145 | "pk": 6, 146 | "fields": { 147 | "created": "2016-01-05T03:15:39.709Z", 148 | "modified": "2016-01-05T03:15:39.709Z", 149 | "gender": "M", 150 | "treatment": "dr", 151 | "first_name": "Roy", 152 | "last_name": "Thomas", 153 | "cpf": "58152293684", 154 | "birthday": "1962-05-14T16:58:44.476Z", 155 | "email": "r.thomas@example.com", 156 | "phone": "(13) 7623-0619", 157 | "blocked": false 158 | } 159 | }, 160 | { 161 | "model": "core.person", 162 | "pk": 7, 163 | "fields": { 164 | "created": "2016-01-05T03:15:39.858Z", 165 | "modified": "2016-01-05T03:15:39.858Z", 166 | "gender": "M", 167 | "treatment": "a", 168 | "first_name": "Edward", 169 | "last_name": "Weeks", 170 | "cpf": "46376850331", 171 | "birthday": "1970-10-07T16:21:38.028Z", 172 | "email": "e.weeks@example.com", 173 | "phone": "(91) 0209-4476", 174 | "blocked": false 175 | } 176 | }, 177 | { 178 | "model": "core.person", 179 | "pk": 8, 180 | "fields": { 181 | "created": "2016-01-05T03:15:40.040Z", 182 | "modified": "2016-01-05T03:15:40.040Z", 183 | "gender": "M", 184 | "treatment": "sr", 185 | "first_name": "William", 186 | "last_name": "Chesley", 187 | "cpf": "73042741070", 188 | "birthday": "1935-10-17T21:56:45.652Z", 189 | "email": "w.chesley@example.com", 190 | "phone": "(95) 2894-4929", 191 | "blocked": false 192 | } 193 | }, 194 | { 195 | "model": "core.person", 196 | "pk": 9, 197 | "fields": { 198 | "created": "2016-01-05T03:15:40.610Z", 199 | "modified": "2016-01-05T03:15:40.610Z", 200 | "gender": "F", 201 | "treatment": "srta", 202 | "first_name": "Carol", 203 | "last_name": "Ruff", 204 | "cpf": "02549446279", 205 | "birthday": "1938-06-26T14:49:22.720Z", 206 | "email": "c.ruff@example.com", 207 | "phone": "(67) 4622-3861", 208 | "blocked": true 209 | } 210 | }, 211 | { 212 | "model": "core.person", 213 | "pk": 10, 214 | "fields": { 215 | "created": "2016-01-05T03:15:40.768Z", 216 | "modified": "2016-01-05T03:15:40.768Z", 217 | "gender": "M", 218 | "treatment": "e", 219 | "first_name": "Jose", 220 | "last_name": "Pisano", 221 | "cpf": "35828715205", 222 | "birthday": "1917-10-30T10:31:48.085Z", 223 | "email": "j.pisano@example.com", 224 | "phone": "(63) 4684-7833", 225 | "blocked": false 226 | } 227 | }, 228 | { 229 | "model": "core.person", 230 | "pk": 11, 231 | "fields": { 232 | "created": "2016-01-05T03:15:40.933Z", 233 | "modified": "2016-01-05T03:15:40.933Z", 234 | "gender": "M", 235 | "treatment": "dr", 236 | "first_name": "Grady", 237 | "last_name": "Dillard", 238 | "cpf": "26903556889", 239 | "birthday": "1972-03-14T01:56:13.237Z", 240 | "email": "g.dillard@example.com", 241 | "phone": "(28) 9676-7472", 242 | "blocked": true 243 | } 244 | }, 245 | { 246 | "model": "core.person", 247 | "pk": 12, 248 | "fields": { 249 | "created": "2016-01-05T03:15:41.097Z", 250 | "modified": "2016-01-05T03:15:41.097Z", 251 | "gender": "M", 252 | "treatment": "sr", 253 | "first_name": "Rodney", 254 | "last_name": "Bishop", 255 | "cpf": "76191023439", 256 | "birthday": "1953-02-04T06:35:43.421Z", 257 | "email": "r.bishop@example.com", 258 | "phone": "(67) 6114-1509", 259 | "blocked": false 260 | } 261 | }, 262 | { 263 | "model": "core.person", 264 | "pk": 13, 265 | "fields": { 266 | "created": "2016-01-05T03:15:41.314Z", 267 | "modified": "2016-01-05T03:15:41.314Z", 268 | "gender": "F", 269 | "treatment": "pa", 270 | "first_name": "Kimberly", 271 | "last_name": "Widrick", 272 | "cpf": "56579138743", 273 | "birthday": "1970-11-14T10:53:17.641Z", 274 | "email": "k.widrick@example.com", 275 | "phone": "(87) 5190-3716", 276 | "blocked": false 277 | } 278 | }, 279 | { 280 | "model": "core.person", 281 | "pk": 14, 282 | "fields": { 283 | "created": "2016-01-05T03:15:41.464Z", 284 | "modified": "2016-01-05T03:15:41.464Z", 285 | "gender": "M", 286 | "treatment": "e", 287 | "first_name": "Roger", 288 | "last_name": "Mills", 289 | "cpf": "89049893340", 290 | "birthday": "1931-10-05T03:12:01.327Z", 291 | "email": "r.mills@example.com", 292 | "phone": "(22) 5993-3306", 293 | "blocked": false 294 | } 295 | }, 296 | { 297 | "model": "core.person", 298 | "pk": 15, 299 | "fields": { 300 | "created": "2016-01-05T03:15:41.622Z", 301 | "modified": "2016-01-05T03:15:41.622Z", 302 | "gender": "F", 303 | "treatment": "srta", 304 | "first_name": "Julie", 305 | "last_name": "Hutchins", 306 | "cpf": "54249454300", 307 | "birthday": "1991-02-26T12:07:20.460Z", 308 | "email": "j.hutchins@example.com", 309 | "phone": "(71) 9075-0587", 310 | "blocked": false 311 | } 312 | }, 313 | { 314 | "model": "core.person", 315 | "pk": 16, 316 | "fields": { 317 | "created": "2016-01-05T03:15:41.799Z", 318 | "modified": "2016-01-05T03:15:41.799Z", 319 | "gender": "M", 320 | "treatment": "p", 321 | "first_name": "Salvatore", 322 | "last_name": "Baker", 323 | "cpf": "44861533064", 324 | "birthday": "1926-01-07T22:59:00.457Z", 325 | "email": "s.baker@example.com", 326 | "phone": "(53) 2243-0147", 327 | "blocked": true 328 | } 329 | }, 330 | { 331 | "model": "core.person", 332 | "pk": 17, 333 | "fields": { 334 | "created": "2016-01-05T03:15:41.960Z", 335 | "modified": "2016-01-05T03:15:41.960Z", 336 | "gender": "F", 337 | "treatment": "d", 338 | "first_name": "Carmen", 339 | "last_name": "Calloway", 340 | "cpf": "16976738352", 341 | "birthday": "1952-05-16T14:59:44.986Z", 342 | "email": "c.calloway@example.com", 343 | "phone": "(71) 6221-0056", 344 | "blocked": true 345 | } 346 | }, 347 | { 348 | "model": "core.person", 349 | "pk": 18, 350 | "fields": { 351 | "created": "2016-01-05T03:15:42.139Z", 352 | "modified": "2016-01-05T03:15:42.139Z", 353 | "gender": "F", 354 | "treatment": "pa", 355 | "first_name": "Lori", 356 | "last_name": "Hamrick", 357 | "cpf": "92625907521", 358 | "birthday": "1980-08-31T15:06:19.670Z", 359 | "email": "l.hamrick@example.com", 360 | "phone": "(50) 8609-3097", 361 | "blocked": true 362 | } 363 | }, 364 | { 365 | "model": "core.person", 366 | "pk": 19, 367 | "fields": { 368 | "created": "2016-01-05T03:15:42.350Z", 369 | "modified": "2016-01-05T03:15:42.350Z", 370 | "gender": "F", 371 | "treatment": "sra", 372 | "first_name": "Marguerite", 373 | "last_name": "Kabel", 374 | "cpf": "22332080357", 375 | "birthday": "1943-11-02T16:47:31.089Z", 376 | "email": "m.kabel@example.com", 377 | "phone": "(10) 2213-7157", 378 | "blocked": false 379 | } 380 | }, 381 | { 382 | "model": "core.person", 383 | "pk": 20, 384 | "fields": { 385 | "created": "2016-01-05T03:15:42.610Z", 386 | "modified": "2016-01-05T03:15:42.610Z", 387 | "gender": "F", 388 | "treatment": "srta", 389 | "first_name": "Diane", 390 | "last_name": "Deleon", 391 | "cpf": "84444913564", 392 | "birthday": "1916-10-03T10:33:59.872Z", 393 | "email": "d.deleon@example.com", 394 | "phone": "(85) 1887-1200", 395 | "blocked": false 396 | } 397 | }, 398 | { 399 | "model": "auth.permission", 400 | "pk": 1, 401 | "fields": { 402 | "name": "Can add log entry", 403 | "content_type": 1, 404 | "codename": "add_logentry" 405 | } 406 | }, 407 | { 408 | "model": "auth.permission", 409 | "pk": 2, 410 | "fields": { 411 | "name": "Can change log entry", 412 | "content_type": 1, 413 | "codename": "change_logentry" 414 | } 415 | }, 416 | { 417 | "model": "auth.permission", 418 | "pk": 3, 419 | "fields": { 420 | "name": "Can delete log entry", 421 | "content_type": 1, 422 | "codename": "delete_logentry" 423 | } 424 | }, 425 | { 426 | "model": "auth.permission", 427 | "pk": 4, 428 | "fields": { 429 | "name": "Can add permission", 430 | "content_type": 2, 431 | "codename": "add_permission" 432 | } 433 | }, 434 | { 435 | "model": "auth.permission", 436 | "pk": 5, 437 | "fields": { 438 | "name": "Can change permission", 439 | "content_type": 2, 440 | "codename": "change_permission" 441 | } 442 | }, 443 | { 444 | "model": "auth.permission", 445 | "pk": 6, 446 | "fields": { 447 | "name": "Can delete permission", 448 | "content_type": 2, 449 | "codename": "delete_permission" 450 | } 451 | }, 452 | { 453 | "model": "auth.permission", 454 | "pk": 7, 455 | "fields": { 456 | "name": "Can add group", 457 | "content_type": 3, 458 | "codename": "add_group" 459 | } 460 | }, 461 | { 462 | "model": "auth.permission", 463 | "pk": 8, 464 | "fields": { 465 | "name": "Can change group", 466 | "content_type": 3, 467 | "codename": "change_group" 468 | } 469 | }, 470 | { 471 | "model": "auth.permission", 472 | "pk": 9, 473 | "fields": { 474 | "name": "Can delete group", 475 | "content_type": 3, 476 | "codename": "delete_group" 477 | } 478 | }, 479 | { 480 | "model": "auth.permission", 481 | "pk": 10, 482 | "fields": { 483 | "name": "Can add user", 484 | "content_type": 4, 485 | "codename": "add_user" 486 | } 487 | }, 488 | { 489 | "model": "auth.permission", 490 | "pk": 11, 491 | "fields": { 492 | "name": "Can change user", 493 | "content_type": 4, 494 | "codename": "change_user" 495 | } 496 | }, 497 | { 498 | "model": "auth.permission", 499 | "pk": 12, 500 | "fields": { 501 | "name": "Can delete user", 502 | "content_type": 4, 503 | "codename": "delete_user" 504 | } 505 | }, 506 | { 507 | "model": "auth.permission", 508 | "pk": 13, 509 | "fields": { 510 | "name": "Can add content type", 511 | "content_type": 5, 512 | "codename": "add_contenttype" 513 | } 514 | }, 515 | { 516 | "model": "auth.permission", 517 | "pk": 14, 518 | "fields": { 519 | "name": "Can change content type", 520 | "content_type": 5, 521 | "codename": "change_contenttype" 522 | } 523 | }, 524 | { 525 | "model": "auth.permission", 526 | "pk": 15, 527 | "fields": { 528 | "name": "Can delete content type", 529 | "content_type": 5, 530 | "codename": "delete_contenttype" 531 | } 532 | }, 533 | { 534 | "model": "auth.permission", 535 | "pk": 16, 536 | "fields": { 537 | "name": "Can add session", 538 | "content_type": 6, 539 | "codename": "add_session" 540 | } 541 | }, 542 | { 543 | "model": "auth.permission", 544 | "pk": 17, 545 | "fields": { 546 | "name": "Can change session", 547 | "content_type": 6, 548 | "codename": "change_session" 549 | } 550 | }, 551 | { 552 | "model": "auth.permission", 553 | "pk": 18, 554 | "fields": { 555 | "name": "Can delete session", 556 | "content_type": 6, 557 | "codename": "delete_session" 558 | } 559 | }, 560 | { 561 | "model": "auth.permission", 562 | "pk": 19, 563 | "fields": { 564 | "name": "Can add contact", 565 | "content_type": 7, 566 | "codename": "add_person" 567 | } 568 | }, 569 | { 570 | "model": "auth.permission", 571 | "pk": 20, 572 | "fields": { 573 | "name": "Can change contact", 574 | "content_type": 7, 575 | "codename": "change_person" 576 | } 577 | }, 578 | { 579 | "model": "auth.permission", 580 | "pk": 21, 581 | "fields": { 582 | "name": "Can delete contact", 583 | "content_type": 7, 584 | "codename": "delete_person" 585 | } 586 | } 587 | ] 588 | -------------------------------------------------------------------------------- /setupfull.sh: -------------------------------------------------------------------------------- 1 | # Shell script to create a full Django project. 2 | # The project contains: 3 | # Core App 4 | # Person Model 5 | # Person List 6 | # Person Detail 7 | # Person Form 8 | # Person Admin 9 | # API REST 10 | # Tests with Selenium 11 | # Fixtures with Generate Random Values 12 | # New commands with django-admin 13 | 14 | # Download: wget --output-document=setupfull.sh URL_NAME 15 | 16 | # Usage: source setupfull.sh 17 | 18 | # Colors 19 | red=`tput setaf 1` 20 | green=`tput setaf 2` 21 | reset=`tput sgr0` 22 | 23 | # default name project 24 | echo "Type the name of project (default: myproject): " 25 | echo "Digite o nome do projeto (default: myproject): " 26 | read p 27 | PROJECT=${p-myproject} 28 | 29 | echo "${green}>>> Remove .venv${reset}" 30 | rm -rf .venv 31 | 32 | echo "${green}>>> Remove djangoproject${reset}" 33 | rm -rf djangoproject 34 | 35 | echo "${green}>>> Creating djangoproject.${reset}" 36 | mkdir djangoproject 37 | cd djangoproject 38 | 39 | echo "${green}>>> Creating virtualenv${reset}" 40 | virtualenv -p python3 .venv 41 | echo "${green}>>> venv is created.${reset}" 42 | 43 | # active 44 | sleep 2 45 | echo "${green}>>> activate the venv.${reset}" 46 | source .venv/bin/activate 47 | 48 | echo "${green}>>> Short the prompt path.${reset}" 49 | PS1="(`basename \"$VIRTUAL_ENV\"`)\e[1;34m:/\W\e[00m$ " 50 | sleep 2 51 | 52 | # installdjango 53 | echo "${green}>>> Installing the Django${reset}" 54 | pip install django djangorestframework django-bootstrap-form django-daterange-filter selenium names rstr pytz 55 | pip freeze > requirements.txt 56 | 57 | # createproject 58 | echo "${green}>>> Creating the project '$PROJECT' ...${reset}" 59 | django-admin.py startproject $PROJECT . 60 | cd $PROJECT 61 | echo "${green}>>> Creating the app 'core' ...${reset}" 62 | python ../manage.py startapp core 63 | cd .. 64 | 65 | # migrate 66 | python manage.py migrate 67 | 68 | # createuser 69 | echo "${green}>>> Creating a 'admin' user ...${reset}" 70 | echo "${green}>>> The password must contain at least 8 characters.${reset}" 71 | echo "${green}>>> Password suggestions: demodemo${reset}" 72 | python manage.py createsuperuser --username='admin' --email='' 73 | 74 | 75 | echo "${green}>>> Editing settings.py${reset}" 76 | sed -i "/django.contrib.staticfiles/a\ '$PROJECT.core'," $PROJECT/settings.py 77 | 78 | 79 | echo "${green}>>> Editing urls.py${reset}" 80 | cat << 'EOF' > $PROJECT/urls.py 81 | from django.conf.urls import url 82 | from django.contrib import admin 83 | import PROJECT.core.views as v 84 | 85 | urlpatterns = [ 86 | url(r'^$', v.home, name='home'), 87 | url(r'^person/$', v.PersonList.as_view(), name='person_list'), 88 | url(r'^person/(?P\d+)/$', v.PersonDetail.as_view(), name='person_detail'), 89 | url(r'^person/add/$', v.PersonCreate.as_view(), name='person_add'), 90 | url(r'^admin/', admin.site.urls), 91 | ] 92 | EOF 93 | 94 | # Editing urls.py 95 | sed -i "s/PROJECT/$PROJECT/" $PROJECT/urls.py 96 | 97 | echo "${green}>>> Editing views.py${reset}" 98 | cat << 'EOF' > $PROJECT/core/views.py 99 | from django.shortcuts import render 100 | from django.http import HttpResponse 101 | from django.core.urlresolvers import reverse_lazy 102 | from django.views.generic import CreateView, TemplateView, ListView, DetailView 103 | from PROJECT.core.models import Person 104 | 105 | 106 | def home(request): 107 | return render(request, 'index.html') 108 | 109 | 110 | class PersonList(ListView): 111 | template_name = 'core/person_list.html' 112 | model = Person 113 | context_object_name = 'persons' 114 | 115 | 116 | class PersonCreate(CreateView): 117 | template_name = 'core/person_form.html' 118 | model = Person 119 | fields = '__all__' 120 | success_url = reverse_lazy('person_list') 121 | 122 | 123 | class PersonDetail(DetailView): 124 | template_name = 'core/person_detail.html' 125 | model = Person 126 | EOF 127 | 128 | # Editing views.py 129 | sed -i "s/PROJECT/$PROJECT/" $PROJECT/core/views.py 130 | 131 | 132 | 133 | echo "${green}>>> Editing models.py${reset}" 134 | cat << 'EOF' > $PROJECT/core/models.py 135 | from django.db import models 136 | from django.core.urlresolvers import reverse_lazy 137 | 138 | gender_list = [('M', 'male'), ('F', 'female')] 139 | 140 | class TimeStampedModel(models.Model): 141 | created = models.DateTimeField(auto_now_add=True, auto_now=False) 142 | modified = models.DateTimeField(auto_now_add=False, auto_now=True) 143 | 144 | class Meta: 145 | abstract = True 146 | 147 | 148 | class Person(TimeStampedModel): 149 | gender = models.CharField(max_length=1, choices=gender_list) 150 | first_name = models.CharField('first name', max_length=30) 151 | last_name = models.CharField('last name', max_length=30) 152 | birthday = models.DateTimeField(null=True, blank=True) 153 | email = models.EmailField(blank=True) 154 | phone = models.CharField(max_length=20, default='') 155 | blocked = models.BooleanField(default=False) 156 | 157 | class Meta: 158 | ordering = ['first_name'] 159 | verbose_name = 'contact' 160 | verbose_name_plural = 'contacts' 161 | 162 | def __str__(self): 163 | return "{} {}".format(self.first_name, self.last_name) 164 | 165 | full_name = property(__str__) 166 | 167 | def get_absolute_url(self): 168 | ''' return id ''' 169 | return reverse_lazy('person_detail', kwargs={'pk': self.pk}) 170 | EOF 171 | 172 | 173 | echo "${green}>>> Editing admin.py${reset}" 174 | cat << 'EOF' > $PROJECT/core/admin.py 175 | from django.contrib import admin 176 | from .models import Person 177 | 178 | admin.site.register(Person) 179 | EOF 180 | 181 | 182 | echo "${green}>>> Editing forms.py${reset}" 183 | cat << 'EOF' > $PROJECT/core/forms.py 184 | from django import forms 185 | from .models import Person 186 | 187 | gender_list = [('M', 'male'), ('F', 'female')] 188 | 189 | 190 | class PersonForm(forms.ModelForm): 191 | gender = forms.ChoiceField( 192 | choices=gender_list, initial='M', widget=forms.RadioSelect) 193 | 194 | class Meta: 195 | model = Person 196 | fields = '__all__' 197 | 198 | def clean_cpf(self): 199 | return self.cleaned_data['cpf'] or None 200 | EOF 201 | 202 | 203 | echo "${green}>>> Creating templates${reset}" 204 | mkdir -p $PROJECT/core/templates/core 205 | touch $PROJECT/core/templates/{base.html,menu.html,index.html,pagination.html} 206 | touch $PROJECT/core/templates/core/{person_list.html,person_detail.html,person_form.html} 207 | 208 | 209 | echo "${green}>>> Migrating${reset}" 210 | python manage.py makemigrations 211 | python manage.py migrate 212 | 213 | echo "${green}>>> Editing base.html${reset}" 214 | 215 | cat << 'EOF' > $PROJECT/core/templates/base.html 216 | 217 | 218 | 219 | {% load static %} 220 | 221 | 222 | 223 | 224 | 225 | 226 | {% block title %} 227 | Django Example 228 | {% endblock title %} 229 | 230 | 231 | 232 | 233 | 234 | 235 | 242 | 243 | 244 | 245 | 246 | {% include "menu.html" %} 247 | 248 | {% block content %} 249 | 250 | {% endblock content %} 251 | 252 | 253 | EOF 254 | 255 | 256 | 257 | echo "${green}>>> Editing menu.html${reset}" 258 | 259 | cat << 'EOF' > $PROJECT/core/templates/menu.html 260 | 261 | 281 | EOF 282 | 283 | 284 | 285 | echo "${green}>>> Editing index.html${reset}" 286 | 287 | cat << 'EOF' > $PROJECT/core/templates/index.html 288 | {% extends "base.html" %} 289 | 290 | {% block content %} 291 |
292 |
293 |

Contacts

294 |

Contacts list make in Django.

295 |

The project contains:

296 |
    297 |
  • Core App
  • 298 |
  • Person Model
  • 299 |
  • Person List
  • 300 |
  • Person Detail
  • 301 |
  • Person Form
  • 302 |
  • Person Admin
  • 303 |
  • API REST
  • 304 |
  • Tests with Selenium
  • 305 |
  • Fixtures with Generate Random Values
  • 306 |
  • New commands with django-admin
  • 307 |
308 |
309 |
310 | {% endblock content %} 311 | EOF 312 | 313 | 314 | 315 | echo "${green}>>> Editing pagination.html${reset}" 316 | 317 | cat << 'EOF' > $PROJECT/core/templates/pagination.html 318 | 319 |
320 |
321 |
    322 | {% if page_obj.has_previous %} 323 |
  • «
  • 324 | {% endif %} 325 | {% for pg in page_obj.paginator.page_range %} 326 | {% if page_obj.number == pg %} 327 |
  • {{ pg }}
  • 328 | {% else %} 329 |
  • {{ pg }}
  • 330 | {% endif %} 331 | {% endfor %} 332 | {% if page_obj.has_next %} 333 |
  • »
  • 334 | {% endif %} 335 |
336 |
337 |
338 | EOF 339 | 340 | 341 | 342 | echo "${green}>>> Editing person_list.html${reset}" 343 | 344 | cat << 'EOF' > $PROJECT/core/templates/core/person_list.html 345 | {% extends "base.html" %} 346 | 347 | {% block content %} 348 | 349 |
350 | 351 | 354 | 355 | {% if persons %} 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | {% for person in persons %} 368 | 369 | 370 | 371 | 372 | 373 | {% if person.blocked %} 374 | 375 | {% else %} 376 | 377 | {% endif %} 378 | 379 | {% endfor %} 380 | 381 |
NameEmailPhoneBirthdayBlocked
{{ person.full_name }}{{ person.email }}{{ person.phone }}{{ person.birthday|date:"d/m/Y" }}
382 | {% else %} 383 |

Without items in this list.

384 | {% endif %} 385 |
386 | {% endblock content %} 387 | EOF 388 | 389 | 390 | echo "${green}>>> Editing person_detail.html${reset}" 391 | 392 | cat << 'EOF' > $PROJECT/core/templates/core/person_detail.html 393 | {% extends "base.html" %} 394 | 395 | {% load static %} 396 | 397 | {% block title %} 398 | Person Detail 399 | {% endblock title %} 400 | 401 | {% block content %} 402 | 403 | 411 | 412 |
413 |
414 | 415 |
416 |
417 | {% if object.treatment %} 418 |

{{ object.get_treatment_display }} {{ object.full_name }}

419 | {% else %} 420 |

{{ object.full_name }}

421 | {% endif %} 422 | {% if object.email %} 423 |

{{ object.email }}

424 | {% endif %} 425 |
426 | 427 |
428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | {% if object.company %} 436 | 437 | 438 | 439 | 440 | {% endif %} 441 | {% if object.occupation %} 442 | 443 | 444 | 445 | 446 | {% endif %} 447 | {% if object.department %} 448 | 449 | 450 | 451 | 452 | {% endif %} 453 | {% if object.phone1 %} 454 | 455 | 456 | 457 | 458 | {% else %} 459 | 460 | 461 | 462 | 463 | {% endif %} 464 | {% if object.phone2 %} 465 | 466 | 467 | 468 | 469 | {% endif %} 470 | {% if object.phone3 %} 471 | 472 | 473 | 474 | 475 | {% endif %} 476 | {% if object.cpf %} 477 | 478 | 479 | 480 | 481 | {% endif %} 482 | {% if object.rg %} 483 | 484 | 485 | 486 | 487 | {% endif %} 488 | {% if object.cnpj %} 489 | 490 | 491 | 492 | 493 | {% endif %} 494 | {% if object.ie %} 495 | 496 | 497 | 498 | 499 | {% endif %} 500 | 501 | 502 | {% if object.active %} 503 | 504 | {% else %} 505 | 506 | {% endif %} 507 | 508 | 509 | 510 | {% if object.blocked %} 511 | 512 | {% else %} 513 | 514 | {% endif %} 515 | 516 | 517 | {% if object.address %} 518 | 519 | 520 | 521 | 522 | {% endif %} 523 | {% if object.complement %} 524 | 525 | 526 | 527 | 528 | {% endif %} 529 | {% if object.district %} 530 | 531 | 532 | 533 | 534 | {% endif %} 535 | {% if object.city %} 536 | 537 | 538 | 539 | 540 | {% endif %} 541 | {% if object.uf %} 542 | 543 | 544 | 545 | 546 | {% endif %} 547 | {% if object.cep %} 548 | 549 | 550 | 551 | 552 | {% endif %} 553 | 554 | 555 |
Gênero{{ object.get_gender_display }}
Empresa{{ object.company }}
Cargo{{ object.occupation }}
Departamento{{ object.department }}
Telefone 1{{ object.phone1 }}
Telefone 1---
Telefone 2{{ object.phone2 }}
Telefone 3{{ object.phone3 }}
CPF{{ object.cpf }}
RG{{ object.rg }}
CNPJ{{ object.cnpj }}
IE{{ object.ie }}
Ativo
Bloqueado
Endereço{{ object.address }}
Complemento{{ object.complement }}
Bairro{{ object.district }}
Cidade{{ object.city }}
UF{{ object.uf }}
CEP{{ object.cep }}
556 |
557 | 558 | {% endblock content %} 559 | EOF 560 | 561 | 562 | echo "${green}>>> Editing person_form.html${reset}" 563 | 564 | cat << 'EOF' > $PROJECT/core/templates/core/person_form.html 565 | 566 | EOF 567 | 568 | 569 | 570 | # Person List 571 | # Person Detail 572 | # Person Form 573 | # Person Admin 574 | # API REST 575 | # Tests with Selenium 576 | # Fixtures with Generate Random Values 577 | # New commands with django-admin 578 | # Gráficos --------------------------------------------------------------------------------