Skip to content

Commit

Permalink
Merge pull request #2 from thorgate/feature/additions
Browse files Browse the repository at this point in the history
Feature/additions
  • Loading branch information
vegetablejuiceftw authored Mar 23, 2018
2 parents 9a43dbf + 07a1195 commit 9f151d4
Show file tree
Hide file tree
Showing 26 changed files with 1,102 additions and 132 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ Ready to contribute? Here's how to set up `tg-apicore` for local development.
5. When you're done making changes, check that your changes pass flake8 and the
tests, including testing other Python versions with tox::

$ flake8 tg_apicore tests
$ python setup.py test or py.test
$ make test
$ make lint
$ tox

To get flake8 and tox, just pip install them into your virtualenv.
Expand Down
10 changes: 10 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
History
=======

Next version
------------------

* Added PageNotFoundView (JSON-based 404 views)
* Added DetailSerializerViewSet (different serializers and queryset for list/detail/edit views)
* Added CreateOnlyFieldsSerializerMixin, ModelValidationSerializerMixin and BaseModelSerializer
* Renamed APIDocumentationView.get_patterns() to .urlpatterns()
* Improved example app a lot. It now also includes tests that partially test tg-apicore itself


0.1.0 (2018-03-08)
------------------

Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ lint: ## check style with flake8
flake8 tg_apicore tests

test: ## run tests quickly with the default Python
py.test
pip install -r requirements_dev.txt
pytest
pytest example/

test-all: ## run tests on every Python version with tox
tox
Expand Down
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Features
* Not interactive yet
* Integrates `JSON API <http://jsonapi.org/>`_
* Cursor pagination with configurable page size
* Viewset classes for using different serializers and querysets for list/detail/edit endpoints
* API-specific 404 view
* Test utilities, e.g. for response validation
* Versioning (WIP)
* Transformer-based approach, inspired by
Expand Down
132 changes: 119 additions & 13 deletions example/companies/api_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"type": "company",
"id": "12",
"attributes": {
"created": "2018-02-21T14:55:06.734781Z",
"created": "2018-03-16T09:38:01.531816Z",
"updated": "2018-03-16T09:38:01.531879Z",
"reg_code": "287-0513",
"name": "Turner and Sons",
"email": "turner@sons.com"
},
Expand Down Expand Up @@ -38,14 +40,16 @@
"type": "company",
"id": "12",
"attributes": {
"created": "2018-02-21T14:55:06.734781Z",
"created": "2018-03-16T09:38:01.531816Z",
"updated": "2018-03-16T09:38:01.531879Z",
"reg_code": "287-0513",
"name": "Turner and Sons",
"email": "turner@sons.com"
},
"relationships": {
"employees": {
"meta": {
"count": 3
"count": 2
},
"data": [
{
Expand All @@ -69,7 +73,8 @@
"type": "employment",
"id": "162",
"attributes": {
"created": "2018-02-21T14:55:06.756900Z",
"created": "2018-03-16T09:48:11.528352Z",
"updated": "2018-03-16T09:48:11.528494Z",
"name": "Linda Burgess",
"email": "carloswoods@griffin.com",
"role": 1
Expand All @@ -82,7 +87,8 @@
"type": "employment",
"id": "91",
"attributes": {
"created": "2018-02-21T14:55:06.755331Z",
"created": "2018-03-16T09:48:11.528352Z",
"updated": "2018-03-16T09:48:11.528494Z",
"name": "Crystal Turner",
"email": "collinsheather@mendoza.biz",
"role": 1
Expand All @@ -98,6 +104,7 @@
"data": {
"type": "company",
"attributes": {
"reg_code": "123-4567",
"name": "Turner and Sons",
"email": "turner@sons.com"
}
Expand All @@ -109,7 +116,8 @@
"type": "company",
"id": "12",
"attributes": {
"created": "2018-02-21T14:55:06.734781Z",
"created": "2018-03-16T09:38:01.531816Z",
"updated": "2018-03-16T09:38:01.531879Z",
"name": "Turner and Sons",
"email": "turner@sons.com"
},
Expand All @@ -124,9 +132,9 @@
(400, {
"errors": [
{
"detail": "Company with this name already exists.",
"detail": "Company with this reg_code already exists.",
"source": {
"pointer": "/data/attributes/name"
"pointer": "/data/attributes/reg_code"
},
"status": "400"
}
Expand All @@ -139,14 +147,16 @@
"type": "company",
"id": "12",
"attributes": {
"created": "2018-02-21T14:55:06.734781Z",
"created": "2018-03-16T09:38:01.531816Z",
"updated": "2018-03-16T09:38:01.531879Z",
"reg_code": "287-0513",
"name": "Turner and Sons",
"email": "turner@sons.com"
},
"relationships": {
"employees": {
"meta": {
"count": 3
"count": 2
},
"data": [
{
Expand All @@ -161,15 +171,16 @@
}
},
"links": {
"self": "%(API_ROOT)s/companies/70/"
"self": "%(API_ROOT)s/companies/12/"
}
},
"included": [
{
"type": "employment",
"id": "162",
"attributes": {
"created": "2018-02-21T14:55:06.756900Z",
"created": "2018-03-16T09:48:11.528352Z",
"updated": "2018-03-16T09:48:11.528494Z",
"name": "Linda Burgess",
"email": "carloswoods@griffin.com",
"role": 1
Expand All @@ -182,7 +193,8 @@
"type": "employment",
"id": "91",
"attributes": {
"created": "2018-02-21T14:55:06.755331Z",
"created": "2018-03-16T09:48:11.528352Z",
"updated": "2018-03-16T09:48:11.528494Z",
"name": "Crystal Turner",
"email": "collinsheather@mendoza.biz",
"role": 1
Expand Down Expand Up @@ -218,3 +230,97 @@
]
}),
]


EMPLOYMENTS_DATA = {
"type": "employment",
"id": "162",
"attributes": {
"created": "2018-03-16T09:48:11.528352Z",
"updated": "2018-03-16T09:48:11.528494Z",
"name": "Linda Burgess",
"email": "carloswoods@griffin.com",
"role": 1
},
"relationships": {
"company": {
"data": {
"type": "company",
"id": "12"
}
}
},
"links": {
"self": "%(API_ROOT)s/employments/162/"
}
}

EMPLOYMENTS_CREATE_REQUEST = {
"data": {
"type": "employment",
"attributes": {
"email": "carloswoods@griffin.com",
},
"relationships": {
"company": {
"data": {"type": "company", "id": "12"}
}
}
}
}

EMPLOYMENTS_CREATE_RESPONSE = {
"data": {
"type": "employment",
"id": "162",
"attributes": {
"created": "2018-03-16T09:48:11.528352Z",
"updated": "2018-03-16T09:48:11.528494Z",
"name": "Linda Burgess",
"email": "carloswoods@griffin.com",
"role": 1
},
"relationships": {
"company": {
"data": {
"type": "company",
"id": "12"
}
}
},
"links": {
"self": "%(API_ROOT)s/employments/162/"
}
},
"included": [
{
"type": "company",
"id": "12",
"attributes": {
"created": "2018-03-16T09:38:01.531816Z",
"updated": "2018-03-16T09:38:01.531879Z",
"reg_code": "287-0513",
"name": "Turner and Sons",
"email": "turner@sons.com"
},
"links": {
"self": "http://localhost:8330/api/2018-02-21/companies/12"
}
}
]
}

EMPLOYMENTS_CREATE_RESPONSES = [
(201, EMPLOYMENTS_CREATE_RESPONSE),
(400, {
"errors": [
{
"detail": "You are not admin in the specified company",
"source": {
"pointer": "/data/attributes/company"
},
"status": "400"
}
]
}),
]
45 changes: 45 additions & 0 deletions example/companies/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import random

import factory
from factory.django import DjangoModelFactory

from companies.models import User, Company, Employment


class UserFactory(DjangoModelFactory):
class Meta:
model = User

password = factory.PostGenerationMethodCall('set_password', 'test')
username = factory.Faker('user_name')
email = factory.Faker('email')
first_name = factory.Faker('first_name')
last_name = factory.Faker('last_name')


class CompanyFactory(DjangoModelFactory):
class Meta:
model = Company

name = factory.Faker('company')
email = factory.Faker('email')
reg_code = factory.Faker('numerify', text='%##-####')


def create_full_example_data():
UserFactory.create_batch(100)
CompanyFactory.create_batch(70)

users = list(User.objects.all())
companies = list(Company.objects.all())

# Generate 300 unique user-company pairs
user_company_pairs = set()
while len(user_company_pairs):
user_company_pairs.add((random.choice(users), random.choice(companies)))

Employment.objects.bulk_create([
Employment(user=user, company=company,
role=Employment.ROLE_ADMIN if random.random() < 0.25 else Employment.ROLE_NORMAL)
for user, company in user_company_pairs
])
49 changes: 2 additions & 47 deletions example/companies/management/commands/create_data.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,10 @@
import random

from django.core.management.base import BaseCommand

import factory
from factory.django import DjangoModelFactory

from companies.models import User, Company, Employment


def faker_with_max_length(provider: str, max_length: int):
return factory.LazyFunction(lambda: factory.Faker(provider).generate({})[:max_length])


def faker_estonian_phone_number():
""" Creates valid Estonian phone numbers.
Numbers beginning with '+37250', followed by 5 or 6 digits are always valid.
"""
return factory.LazyFunction(lambda: ('+37250%06d' % random.randint(0, 999999)))


class UserFactory(DjangoModelFactory):
class Meta:
model = User

password = factory.PostGenerationMethodCall('set_password', 'test')
username = factory.Faker('user_name')
email = factory.Faker('email')
first_name = factory.Faker('first_name')
last_name = factory.Faker('last_name')


class CompanyFactory(DjangoModelFactory):
class Meta:
model = Company

name = factory.Faker('company')
email = factory.Faker('email')
from companies.factories import create_full_example_data


class Command(BaseCommand):
help = "Create test data"

def handle(self, *args, **options):
UserFactory.create_batch(100)
CompanyFactory.create_batch(70)

users = list(User.objects.all())
companies = list(Company.objects.all())

Employment.objects.bulk_create([
Employment(user=random.choice(users), company=random.choice(companies),
role=Employment.ROLE_MANAGER if random.random() < 0.25 else Employment.ROLE_NORMAL)
for _ in range(300)
])
create_full_example_data()
Loading

0 comments on commit 9f151d4

Please sign in to comment.