diff --git a/api/urls.py b/api/urls.py index e0a3b38..e8b90c2 100755 --- a/api/urls.py +++ b/api/urls.py @@ -18,6 +18,8 @@ from .views import ( StageViewSet, TeamViewSet, UserViewSet, + WorkSellPhotoViewSet, + WorkSellViewSet, ) @@ -40,5 +42,7 @@ router.register(r'specializations', SpecializationViewSet) router.register(r'stages', StageViewSet) router.register(r'teams', TeamViewSet) router.register(r'users', UserViewSet) +router.register(r'work-sell-photos', WorkSellPhotoViewSet) +router.register(r'work-sells', WorkSellViewSet) urlpatterns = router.urls diff --git a/api/views.py b/api/views.py index a998e92..7c05923 100755 --- a/api/views.py +++ b/api/views.py @@ -1,13 +1,20 @@ +from django.conf import settings from django.db.models import Q -from rest_framework.viewsets import ModelViewSet from rest_framework import permissions +from rest_framework.pagination import PageNumberPagination +from rest_framework.viewsets import ModelViewSet from projects.models import Project, Realty, Stage, Portfolio, PortfolioPhoto, Answer, AnswerFile, Order -from projects.serializers import (ProjectSerializer, RealtySerializer, StageSerializer, - PortfolioSerializer, PortfolioPhotoSerializer, AnswerSerializer, - OrderSerializer, AnswerFileSerializer,) -from projects.filters import (ProjectFilterSet, RealtyFilterSet, StageFilterSet, PortfolioFilterSet, - OrderFilterSet, PortfolioPhotoFilterSet,) + +from projects.serializers import ( + ProjectSerializer, RealtySerializer, StageSerializer, PortfolioSerializer, + PortfolioPhotoSerializer, AnswerSerializer, OrderSerializer, AnswerFileSerializer, +) + +from projects.filters import ( + ProjectFilterSet, RealtyFilterSet, StageFilterSet, PortfolioFilterSet, OrderFilterSet, + PortfolioPhotoFilterSet, +) from specializations.models import Specialization from specializations.serializers import SpecializationSerializer @@ -29,6 +36,10 @@ from reviews.models import Review from reviews.serializers import ReviewSerializer from reviews.filters import ReviewFilterSet +from work_sell.models import WorkSell, WorkSellPhoto +from work_sell.serializers import WorkSellSerializer, WorkSellPhotoSerializer +from work_sell.filters import WorkSellFilterSet, WorkSellPhotoFilterSet + class ContractorResumeFilesViewSet(ModelViewSet): queryset = ContractorResumeFiles.objects.all() @@ -142,10 +153,19 @@ class LocationViewSet(ModelViewSet): filter_class = LocationFilterSet + + +class PortfolioPagination(PageNumberPagination): + page_size = settings.API_PAGE_SIZE # Default page size + page_size_query_param = 'page_size' # Provide custom page size through a query param + max_page_size = 1000 + class PortfolioViewSet(ModelViewSet): queryset = Portfolio.objects.all() serializer_class = PortfolioSerializer filter_class = PortfolioFilterSet + pagination_class = PortfolioPagination + class PortfolioPhotoViewSet(ModelViewSet): @@ -154,6 +174,29 @@ class PortfolioPhotoViewSet(ModelViewSet): filter_class = PortfolioPhotoFilterSet + + +class WorkSellPagination(PageNumberPagination): + page_size = settings.API_PAGE_SIZE # Default page size + page_size_query_param = 'page_size' # Provide custom page size through a query param + max_page_size = 1000 + +class WorkSellViewSet(ModelViewSet): + queryset = WorkSell.objects.all() + serializer_class = WorkSellSerializer + filter_class = WorkSellFilterSet + pagination_class = WorkSellPagination + + + +class WorkSellPhotoViewSet(ModelViewSet): + queryset = WorkSellPhoto.objects.all() + serializer_class = WorkSellPhotoSerializer + filter_class = WorkSellPhotoFilterSet + + + + class AnswerViewSet(ModelViewSet): queryset = Answer.objects.all() serializer_class = AnswerSerializer diff --git a/archilance/management/commands/generate_work_sells.py b/archilance/management/commands/generate_work_sells.py new file mode 100644 index 0000000..daef0ec --- /dev/null +++ b/archilance/management/commands/generate_work_sells.py @@ -0,0 +1,51 @@ +from django.contrib.auth.models import Group, Permission +from django.contrib.contenttypes.models import ContentType +from django.core.management import BaseCommand +from django.utils import timezone +import pydash as _; _.map = _.map_; _.filter = _.filter_ +import random + +from archilance import util +from common.models import Location +from projects.models import TERMS, CURRENCIES, BuildingClassfication, ConstructionType +from specializations.models import Specialization +from users.models import User +from work_sell.models import WorkSell, WorkSellPhoto + + +class Command(BaseCommand): + def handle(self, *args, **options): + print('---------------------------------------') + print('Generating work sells...') + print('---------------------------------------') + + def create_work_sell(i): + ws = WorkSell( + budget=util.random_amount(), + created=util.random_date(), + currency=_.sample(CURRENCIES)[0], + description=util.lorem(), + name=util.lorem(words=_.random(2, 20), sentences=1), + term=_.random(0, 20), + term_type=_.sample(TERMS)[0], + ) + + ws.save() + + ws.user = User.contractor_objects.order_by('?').first() + ws.building_classification = BuildingClassfication.objects.order_by('?').first() + ws.construction_type = ConstructionType.objects.order_by('?').first() + ws.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() + ws.specialization = Specialization.objects.root_nodes()[0].get_descendants().order_by('?').first() + + pic_names = _.split('a.png b.png c.jpg d.png e.jpg f.png g.png h.jpg i.png j.png k.jpg l.png m.png n.png o.png p.png q.jpg', ' ') + + _.times( + lambda i_: ws.photos.create(img='_sample_files/%s' % util.take_one_random(pic_names)), + _.random(1, 15), + ) + + ws.save() + return ws + + _.times(create_work_sell, 1000) diff --git a/archilance/settings/base.py b/archilance/settings/base.py index db32bcf..c17774f 100644 --- a/archilance/settings/base.py +++ b/archilance/settings/base.py @@ -256,6 +256,9 @@ LOGIN_URL = '/users/login/' if DEBUG: EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' +PAGE_SIZE = 10 # Non-api page size (regular views) +API_PAGE_SIZE = 100 # Django REST framework + REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', @@ -267,7 +270,7 @@ REST_FRAMEWORK = { # 'rest_framework.permissions.DjangoModelPermissions', ], - 'PAGE_SIZE': 100, + 'PAGE_SIZE': API_PAGE_SIZE, 'DEFAULT_FILTER_BACKENDS': ('rest_framework_filters.backends.DjangoFilterBackend',), # djangorestframework-filters } @@ -293,8 +296,6 @@ SHELL_PLUS_POST_IMPORTS = ( # Extra auto imports ('pprint', ('pprint', 'pformat')), ) -PAGE_SIZE = 10 # Pagination - YANDEX_MONEY = {'shop_password': 'x1uvmS9Iq8WBE3Oo'} diff --git a/archilance/util.py b/archilance/util.py index 361b400..7a06ed8 100644 --- a/archilance/util.py +++ b/archilance/util.py @@ -82,8 +82,8 @@ def model_fields(model, width=200): ) for f in fields], width=width) -def lorem(sentences=5): - words = _.split(( +def lorem(words=None, sentences=5): + vocab = _.split(( 'a ac adipiscing amet ante arcu at auctor augue bibendum commodo condimentum consectetur consequat convallis curabitur' 'cursus diam dictum dignissim dolor donec duis efficitur eget eleifend elit enim erat et eu ex facilisis faucibus feugiat' 'finibus gravida iaculis id imperdiet in integer ipsum lacinia lacus laoreet lectus leo libero ligula lobortis lorem' @@ -93,7 +93,7 @@ def lorem(sentences=5): 'vitae viverra volutpat vulputate' ), ' ') - return _.join(_.times(lambda i_: _.capitalize(_.join(_.sample(words, _.random(5, 30)), ' ')), sentences), '. ') + return _.join(_.times(lambda i_: _.capitalize(_.join(_.sample(vocab, words or _.random(5, 30)), ' ')), sentences), '. ') def decap(s): diff --git a/projects/filters.py b/projects/filters.py index f5b42f9..5f20c98 100755 --- a/projects/filters.py +++ b/projects/filters.py @@ -103,6 +103,7 @@ class PortfolioFilterSet(FilterSet): term_type = AllLookupsFilter() photos = RelatedFilter('projects.filters.PortfolioPhotoFilterSet') + user = RelatedFilter('users.filters.UserFilterSet') class Meta: model = Portfolio diff --git a/projects/models.py b/projects/models.py index b1d6f8d..bec87d0 100644 --- a/projects/models.py +++ b/projects/models.py @@ -288,7 +288,7 @@ class Portfolio(models.Model): budget = models.DecimalField(max_digits=10, decimal_places=0, default=0, null=True, blank=True) building_classification = models.ForeignKey(BuildingClassfication, related_name='portfolios', null=True, blank=True) construction_type = models.ForeignKey(ConstructionType, related_name='portfolios', null=True, blank=True) - created = models.DateTimeField(default=timezone.now, auto_now_add=True, auto_created=True) + created = models.DateTimeField(auto_now_add=True, auto_created=True) currency = models.CharField(max_length=20, default='rur', choices=CURRENCIES, null=True, blank=True) description = models.TextField() location = TreeForeignKey('common.Location', related_name='portfolios', null=True, blank=True) diff --git a/projects/serializers.py b/projects/serializers.py index 48df52c..3d5ef39 100755 --- a/projects/serializers.py +++ b/projects/serializers.py @@ -1,5 +1,5 @@ from generic_relations.relations import GenericRelatedField -from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField, PrimaryKeyRelatedField +from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField, PrimaryKeyRelatedField, ReadOnlyField from .models import Project, Realty, BuildingClassfication, ConstructionType, Order, Stage, Portfolio, PortfolioPhoto, Answer, AnswerFile from common.serializers import LocationSerializer @@ -7,7 +7,6 @@ from specializations.serializers import SpecializationSerializer from users.models import User, Team from users.serializers import UserSerializer, TeamSerializer - class BuildingClassficationSerializer(ModelSerializer): class Meta: model = BuildingClassfication @@ -47,7 +46,6 @@ class RealtySerializer(ModelSerializer): ) - class StageSerializer(ModelSerializer): # order = OrderSerializer() @@ -101,7 +99,6 @@ class OrderSerializer(ModelSerializer): ) - class ProjectSerializer(ModelSerializer): customer = UserSerializer() specialization = SpecializationSerializer() @@ -149,6 +146,7 @@ class PortfolioSerializer(ModelSerializer): # answers = AnswerSerializer(many=True) building_classification = BuildingClassficationSerializer() construction_type = ConstructionTypeSerializer() + id = ReadOnlyField() location = LocationSerializer() photos = PortfolioPhotoSerializer(many=True) specialization = SpecializationSerializer() diff --git a/users/serializers.py b/users/serializers.py index 56bc196..96df7b4 100755 --- a/users/serializers.py +++ b/users/serializers.py @@ -1,4 +1,4 @@ -from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField +from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField, ReadOnlyField from .models import User, Team, ContractorResumeFiles, ContractorResume from projects.models import Project @@ -34,6 +34,7 @@ class ContractorResumeFilesSerializer(ModelSerializer): class UserSerializer(ModelSerializer): _type = SerializerMethodField() # Distinguish when used with generic serializers + id = ReadOnlyField() class Meta: model = User @@ -81,18 +82,18 @@ class UserSerializer(ModelSerializer): class TeamSerializer(ModelSerializer): _type = SerializerMethodField() # Distinguish when used with generic serializers + # answers = AnswerSerializer(many=True) avatar = ImageField() contractors = UserSerializer(many=True) owner = UserSerializer() specializations = SpecializationSerializer(many=True) - # answers = AnswerSerializer(many=True) class Meta: model = Team fields = ( '_type', - 'answers', + # 'answers', 'avatar', 'contractors', 'created', diff --git a/users/templates/contractor_office.html b/users/templates/contractor_office.html index 6b78b0a..14bf3e1 100644 --- a/users/templates/contractor_office.html +++ b/users/templates/contractor_office.html @@ -159,61 +159,55 @@
-
- {% for p in portfolios %} +
+
-
-
- {% for ws in work_sells %} +
+
- @@ -254,3 +248,69 @@
{% endblock %} + +{% block js_block %} + +{% endblock %} diff --git a/work_sell/filters.py b/work_sell/filters.py index fd1221b..b37581f 100644 --- a/work_sell/filters.py +++ b/work_sell/filters.py @@ -1,6 +1,8 @@ import django_filters +from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter + +from work_sell.models import WorkSell, WorkSellPhoto -from work_sell.models import WorkSell class WorkSellFilter(django_filters.FilterSet): budget = django_filters.NumberFilter() @@ -10,3 +12,32 @@ class WorkSellFilter(django_filters.FilterSet): class Meta: model = WorkSell + +class WorkSellPhotoFilterSet(FilterSet): + id = AllLookupsFilter() + work_sell = RelatedFilter('work_sell.filters.WorkSellFilterSet') + # img = ??? + + class Meta: + model = WorkSellPhoto + + +class WorkSellFilterSet(FilterSet): + budget = AllLookupsFilter() + created = AllLookupsFilter() + currency = AllLookupsFilter() + description = AllLookupsFilter() + id = AllLookupsFilter() + name = AllLookupsFilter() + term = AllLookupsFilter() + term_type = AllLookupsFilter() + + building_classification = RelatedFilter('projects.filters.BuildingClassficationFilterSet') + construction_type = RelatedFilter('projects.filters.ConstructionTypeFilterSet') + contractor = RelatedFilter('users.filters.UserFilterSet') + location = RelatedFilter('common.filters.LocationFilterSet') + photos = RelatedFilter('work_sell.filters.WorkSellPhotoFilterSet') + specialization = RelatedFilter('specializations.filters.SpecializationFilterSet') + + class Meta: + model = WorkSell diff --git a/work_sell/models.py b/work_sell/models.py index b028027..d1ed8bd 100644 --- a/work_sell/models.py +++ b/work_sell/models.py @@ -1,9 +1,7 @@ -from mptt.models import TreeForeignKey -from sorl.thumbnail import ImageField - from django.db import models - from django.utils import timezone +from mptt.models import TreeForeignKey +from sorl.thumbnail import ImageField from users.models import User, Team from projects.models import BuildingClassfication, ConstructionType, TERMS, CURRENCIES @@ -17,7 +15,7 @@ class WorkSell(models.Model): building_classification = models.ForeignKey(BuildingClassfication, related_name='worksells', null=True, blank=True) construction_type = models.ForeignKey(ConstructionType, related_name='worksells', null=True, blank=True) contractor = models.ForeignKey(User, related_name='work_sell', null=True, blank=True) # TODO: Pluralize related name - created = models.DateTimeField(default=timezone.now, auto_now_add=True) + created = models.DateTimeField(auto_now_add=True) currency = models.CharField(max_length=20, default='rur', choices=CURRENCIES, null=True, blank=True) description = models.TextField(blank=True) location = TreeForeignKey('common.Location', related_name='worksells', null=True, blank=True) diff --git a/work_sell/serializers.py b/work_sell/serializers.py new file mode 100644 index 0000000..35c4c2e --- /dev/null +++ b/work_sell/serializers.py @@ -0,0 +1,52 @@ +from generic_relations.relations import GenericRelatedField +from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField, PrimaryKeyRelatedField, ReadOnlyField + +from .models import WorkSell, WorkSellPhoto +from common.serializers import LocationSerializer +from projects.serializers import BuildingClassficationSerializer, ConstructionTypeSerializer +from specializations.serializers import SpecializationSerializer +from users.serializers import UserSerializer + + +class WorkSellPhotoSerializer(ModelSerializer): + img = ImageField() + worksell_id = PrimaryKeyRelatedField(read_only=True, source='worksell') + + class Meta: + model = WorkSellPhoto + + fields = ( + 'id', + 'img', + 'worksell_id', + ) + + +class WorkSellSerializer(ModelSerializer): + building_classification = BuildingClassficationSerializer() + construction_type = ConstructionTypeSerializer() + contractor = UserSerializer() + id = ReadOnlyField() + location = LocationSerializer() + photos = WorkSellPhotoSerializer(many=True) + specialization = SpecializationSerializer() + + class Meta: + model = WorkSell + + fields = ( + 'budget', + 'building_classification', + 'construction_type', + 'contractor', + 'created', + 'currency', + 'description', + 'id', + 'location', + 'name', + 'photos', + 'specialization', + 'term', + 'term_type', + )