diff --git a/api/urls.py b/api/urls.py index 176d031..9b19b2c 100755 --- a/api/urls.py +++ b/api/urls.py @@ -1,34 +1,42 @@ from rest_framework import routers from .views import ( + AnswerViewSet, + ContractorResumeFilesViewSet, + ContractorResumeViewSet, + DocumentViewSet, LocationViewSet, + MessageViewSet, + NoteViewSet, + PortfolioPhotoViewSet, + PortfolioViewSet, ProjectViewSet, RealtyViewSet, + ReviewViewSet, SpecializationViewSet, - UserViewSet, - MessageViewSet, StageViewSet, - NoteViewSet, - DocumentViewSet, - ReviewViewSet, - ContractorResumeViewSet, - ContractorResumeFilesViewSet, + TeamViewSet, + UserViewSet, ) router = routers.DefaultRouter() -router.register(r'locations', LocationViewSet) -router.register(r'projects', ProjectViewSet) -router.register(r'stages', StageViewSet) -router.register(r'reviews', ReviewViewSet) +router.register(r'answers', AnswerViewSet) router.register(r'contractorresume', ContractorResumeViewSet) router.register(r'contractorresumefiles', ContractorResumeFilesViewSet) router.register(r'documents', DocumentViewSet) +router.register(r'locations', LocationViewSet) +router.register(r'message', MessageViewSet) +router.register(r'note', NoteViewSet) +router.register(r'portfolio-photos', PortfolioPhotoViewSet) +router.register(r'portfolios', PortfolioViewSet) +router.register(r'projects', ProjectViewSet) router.register(r'realties', RealtyViewSet) +router.register(r'reviews', ReviewViewSet) router.register(r'specializations', SpecializationViewSet) +router.register(r'stages', StageViewSet) +router.register(r'teams', TeamViewSet) router.register(r'users', UserViewSet) -router.register(r'message', MessageViewSet) -router.register(r'note', NoteViewSet) urlpatterns = router.urls diff --git a/api/views.py b/api/views.py index 49d7f8d..502ba87 100755 --- a/api/views.py +++ b/api/views.py @@ -2,16 +2,16 @@ from django.db.models import Q from rest_framework.viewsets import ModelViewSet from rest_framework import permissions -from projects.models import Project, Realty, Stage -from projects.serializers import ProjectSerializer, RealtySerializer, StageSerializer -from projects.filters import ProjectFilterSet, RealtyFilterSet, StageFilterSet +from projects.models import Project, Realty, Stage, Portfolio, PortfolioPhoto, Answer, AnswerFile +from projects.serializers import ProjectSerializer, RealtySerializer, StageSerializer, PortfolioSerializer, PortfolioPhotoSerializer, AnswerSerializer, AnswerFileSerializer +from projects.filters import ProjectFilterSet, RealtyFilterSet, StageFilterSet, PortfolioFilterSet, PortfolioPhotoFilterSet from specializations.models import Specialization from specializations.serializers import SpecializationSerializer from specializations.filters import SpecializationFilterSet -from users.models import User, ContractorResumeFiles, ContractorResume -from users.serializers import UserSerializer, ContractorResumeFilesSerializer, ContractorResumeSerializer +from users.models import User, ContractorResumeFiles, ContractorResume, Team +from users.serializers import UserSerializer, ContractorResumeFilesSerializer, ContractorResumeSerializer, TeamSerializer from users.filters import UserFilterSet, ContractorResumeFilesFilterSet, ContractorResumeFilterSet from common.models import Location @@ -101,7 +101,7 @@ class SpecializationViewSet(ModelViewSet): try: # TODO: dirty queryset = Specialization.objects.root_nodes()[0].get_descendants() except: - queryset = Specialization.objects + queryset = Specialization.objects.all() serializer_class = SpecializationSerializer filter_class = SpecializationFilterSet @@ -116,6 +116,30 @@ class LocationViewSet(ModelViewSet): try: # TODO: dirty queryset = Location.objects.root_nodes()[0].get_descendants() except: - queryset = Location.objects + queryset = Location.objects.all() serializer_class = LocationSerializer filter_class = LocationFilterSet + + +class PortfolioViewSet(ModelViewSet): + queryset = Portfolio.objects.all() + serializer_class = PortfolioSerializer + filter_class = PortfolioFilterSet + + +class PortfolioPhotoViewSet(ModelViewSet): + queryset = PortfolioPhoto.objects.all() + serializer_class = PortfolioPhotoSerializer + filter_class = PortfolioPhotoFilterSet + + +class AnswerViewSet(ModelViewSet): + queryset = Answer.objects.all() + serializer_class = AnswerSerializer + # filter_class = AnswerFilterSet + + +class TeamViewSet(ModelViewSet): + queryset = Team.objects.all() + serializer_class = TeamSerializer + # filter_class = TeamFilterSet diff --git a/archilance/settings/base.py b/archilance/settings/base.py index f615008..94b91cd 100644 --- a/archilance/settings/base.py +++ b/archilance/settings/base.py @@ -12,7 +12,7 @@ SECRET_KEY = 'vb6@b9zj7^f!^+x*e8=e!oundyu1!e*&0i(3gu2xwo4%fx4h&n' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -TEMPLATE_DEBUG = True # Show debug info in templates. See `projects/templates/project_filter.html` +# TEMPLATE_DEBUG = True # Show debug info in templates. See `projects/templates/project_filter.html` ALLOWED_HOSTS = [] @@ -39,6 +39,7 @@ THIRD_PARTY_APPS = [ 'compressor', 'password_reset', 'mathfilters', # Basic math operations in templates; https://pypi.python.org/pypi/django-mathfilters + 'generic_relations', # https://github.com/Ian-Foote/rest-framework-generic-relations ] LOCAL_APPS = [ diff --git a/assets/index.js b/assets/index.js index 9d393e9..db0d0db 100644 --- a/assets/index.js +++ b/assets/index.js @@ -315,6 +315,21 @@ $fileUploadContainer.on('click', '.existing-file-remove-btn', function($evt) { +// Project answer portfolio selection ---------------------- + + +//function ...() { +// +//} + + + + + + + + + // Helpers --------------------------------------------- diff --git a/projects/filters.py b/projects/filters.py index 444d426..f5b42f9 100755 --- a/projects/filters.py +++ b/projects/filters.py @@ -1,6 +1,6 @@ from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter -from .models import Project, Stage, Order, Realty, BuildingClassfication, ConstructionType +from .models import Project, Stage, Order, Realty, BuildingClassfication, ConstructionType, Portfolio, PortfolioPhoto class BuildingClassficationFilterSet(FilterSet): @@ -83,3 +83,26 @@ class RealtyFilterSet(FilterSet): class Meta: model = Realty + + +class PortfolioPhotoFilterSet(FilterSet): + id = AllLookupsFilter() + portfolio = RelatedFilter('projects.filters.PortfolioFilterSet') + # img = ??? + + class Meta: + model = PortfolioPhoto + + +class PortfolioFilterSet(FilterSet): + budget = AllLookupsFilter() + currency = AllLookupsFilter() + id = AllLookupsFilter() + name = AllLookupsFilter() + term = AllLookupsFilter() + term_type = AllLookupsFilter() + + photos = RelatedFilter('projects.filters.PortfolioPhotoFilterSet') + + class Meta: + model = Portfolio diff --git a/projects/migrations/0005_auto_20160812_1956.py b/projects/migrations/0005_auto_20160812_1956.py new file mode 100644 index 0000000..c73cf89 --- /dev/null +++ b/projects/migrations/0005_auto_20160812_1956.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-12 16:56 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0004_merge'), + ] + + operations = [ + migrations.AlterField( + model_name='answer', + name='portfolios', + field=models.ManyToManyField(blank=True, related_name='answers', to='projects.Portfolio'), + ), + ] diff --git a/projects/models.py b/projects/models.py index da2b19b..0c6cfc7 100644 --- a/projects/models.py +++ b/projects/models.py @@ -121,7 +121,7 @@ class Answer(models.Model): budget = models.DecimalField(max_digits=10, decimal_places=0) created = models.DateTimeField(default=timezone.now) currency = models.CharField(max_length=5, choices=CURRENCIES, default='rur') - portfolios = models.ManyToManyField('Portfolio', related_name ='portfolios_answers', blank=True) + portfolios = models.ManyToManyField('Portfolio', related_name ='answers', blank=True) project = models.ForeignKey(Project, related_name='answers') secure_deal_only = models.BooleanField(default=False) term = models.IntegerField(default=0) diff --git a/projects/serializers.py b/projects/serializers.py index 5d8fdba..89fd9f7 100755 --- a/projects/serializers.py +++ b/projects/serializers.py @@ -1,9 +1,11 @@ -from rest_framework.serializers import ModelSerializer +from generic_relations.relations import GenericRelatedField +from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField, PrimaryKeyRelatedField -from .models import Project, Realty, BuildingClassfication, ConstructionType, Order, Stage +from .models import Project, Realty, BuildingClassfication, ConstructionType, Order, Stage, Portfolio, PortfolioPhoto, Answer, AnswerFile from common.serializers import LocationSerializer from specializations.serializers import SpecializationSerializer -from users.serializers import UserSerializer +from users.models import User, Team +from users.serializers import UserSerializer, TeamSerializer class BuildingClassficationSerializer(ModelSerializer): @@ -120,3 +122,94 @@ class ProjectSerializer(ModelSerializer): 'text', 'work_type', ) + + +class PortfolioPhotoSerializer(ModelSerializer): + img = ImageField() + portfolio_id = PrimaryKeyRelatedField(read_only=True, source='portfolio') + + class Meta: + model = PortfolioPhoto + + fields = ( + 'id', + 'img', + 'portfolio_id', + ) + + +class PortfolioSerializer(ModelSerializer): + # answers = AnswerSerializer(many=True) + building_classification = BuildingClassficationSerializer() + construction_type = ConstructionTypeSerializer() + location = LocationSerializer() + photos = PortfolioPhotoSerializer(many=True) + specialization = SpecializationSerializer() + user = UserSerializer() + + class Meta: + model = Portfolio + + fields = ( + # 'answers', + 'budget', + 'building_classification', + 'construction_type', + 'currency', + 'description', + 'id', + 'location', + 'name', + 'photos', + 'specialization', + 'term', + 'term_type', + 'user', + 'worksell', + ) + + +class AnswerFileSerializer(ModelSerializer): + file = FileField() + + class Meta: + model = AnswerFile + + fields = ( + 'file', + 'id', + 'name', + # 'answer', + ) + + +class AnswerSerializer(ModelSerializer): + files = AnswerFileSerializer(many=True) + portfolios = PortfolioSerializer(many=True) + project = ProjectSerializer + + author = GenericRelatedField({ + User: UserSerializer(), + Team: TeamSerializer() + }) + + class Meta: + model = Answer + + fields = ( + 'budget', + 'created', + 'currency', + 'id', + 'secure_deal_only', + 'term', + 'term_type', + 'text', + + 'files', + 'portfolios', + 'project', + 'author', # Generic related field + + # 'candidates', + ) diff --git a/projects/templates/project_detail.html b/projects/templates/project_detail.html index cb431a2..45a9d37 100644 --- a/projects/templates/project_detail.html +++ b/projects/templates/project_detail.html @@ -215,20 +215,18 @@ - {% if answer.author|class_name == 'User' %} - {% if answer.author.cro %} -
-
-

Есть допуск СРО

-
- {% endif %} + {% if answer.author|class_name == 'User' and answer.author.cro %} +
+
+

Есть допуск СРО

+
{% elif answer.author|class_name == 'Team' %} -{# {% if any of these motherfuckers "answer.author.contractors.all" got a cro, then... %}#} -
-
-

Есть допуск СРО

-
-{# {% endif %}#} + + +
+
+

Есть допуск СРО

+
{% endif %}
@@ -238,9 +236,9 @@

- Срок: {{ answer.term }} {{ answer.get_term_type_display|decap }} + Срок: {{ answer.term }} {{ answer.get_currency_display }} {{ answer.get_term_type_display|decap }}

-

Опубликован: {{ answer.created }}

+

Опубликован: {{ answer.created|date:'M d, Y' }}

@@ -358,6 +356,18 @@
+ +
+ {% for x in 'abc' %} +
+
+
+
+
+
+
+ {% endfor %} +
@@ -417,7 +427,7 @@ - {% elif request.user.is_customer %} + {% elif request.user.is_customer and project.answers.exists %} @@ -448,10 +458,6 @@
-
-

Новые исполнители

-
- @@ -459,126 +465,137 @@ +
+

Новые исполнители

+
- {% for answer_p in project.answers.all %} -
-
- -
- {% ratings_widget answer_p.author.pk 'restList2' %} - {% if answer_p.author.cro %} -
-
-

Есть допуск СРО

-
- {% endif %} -
-
-

Цена: - {{ answer_p.budget }} - -

-

- Срок: {{ answer_p.term }} of {{ answer_p.term_type }} -

-

Опубликован: {{ answer_p.created | date:"M d, Y" }}

-
- -
-
-
-
-
+ {% for answer in project.answers.all %} +
+
+ + + +

+ {% if answer.author|class_name == 'User' %} + {{ answer.author.get_full_name }} [{{ answer.author.username }}] + {% elif answer.author|class_name == 'Team' %} + {{ answer.author.name }} + {% endif %} +

+ + + + {% if answer.author|class_name == 'User' %} + {% if answer.author.contractor_status == 'free' %} +
Свободен
+ {% endif %} + {% endif %}
-
-
-
-
+ +
+ {% ratings_widget answer.author.pk 'restList2' %} + + {% if answer.author|class_name == 'User' and answer.author.cro %} +
+
+

Есть допуск СРО

-
-
-
-
-
-
+ {% elif answer.author|class_name == 'Team' %} + + +
+
+

Есть допуск СРО

-
+ {% endif %}
-
-
-
-
+ +
+

+ Цена: + {{ answer.budget|intcomma }} + +

+

+ Срок: {{ answer.term }} {{ answer.get_currency_display }} {{ answer.get_term_type_display|decap }} +

+

Опубликован: {{ answer.created|date:'M d, Y' }}

+
+ + + +
+ {% for portf in answer.portfolios.all %} +
+
+
+
+
+
-
+ {% endfor %}
-
-
-
-
-

- Иванов Петр Иванович -

- - 13.01.2016 / 21:05 - -
- - - - - + +
+
+
+

+ Иванов Петр Иванович +

+ + 13.01.2016 / 21:05 + +
+ + + + + +
+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar tempor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus sapien nunc eget odio. +

-

- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar tempor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus sapien nunc eget odio. -

-
-
-
-

- Иванов Петр Иванович -

- - 13.01.2016 / 21:05 - -

- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar tempor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus sapien nunc eget odio. -

- - Ответить - +
+
+

+ Иванов Петр Иванович +

+ + 13.01.2016 / 21:05 + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar tempor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus sapien nunc eget odio. +

+ + Ответить + +
-
{% endfor %} {% endif %} diff --git a/requirements/base.txt b/requirements/base.txt index 0e1edab..cb63921 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -39,3 +39,4 @@ tornado==4.3 natsort django-mathfilters gunicorn==19.6.0 +rest-framework-generic-relations diff --git a/users/serializers.py b/users/serializers.py index 9f21146..56bc196 100755 --- a/users/serializers.py +++ b/users/serializers.py @@ -1,7 +1,9 @@ -from rest_framework.serializers import ModelSerializer +from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField from .models import User, Team, ContractorResumeFiles, ContractorResume from projects.models import Project +# from projects.serializers import AnswerSerializer +from specializations.serializers import SpecializationSerializer class ContractorResumeSerializer(ModelSerializer): @@ -30,32 +32,22 @@ class ContractorResumeFilesSerializer(ModelSerializer): ) -class TeamSerializer(ModelSerializer): - class Meta: - model = Team - - fields = ( - 'created', - 'name', - 'owner', - 'specializations', - 'users', - ) - - class UserSerializer(ModelSerializer): + _type = SerializerMethodField() # Distinguish when used with generic serializers + class Meta: model = User fields = ( + '_type', 'avatar', - 'financial_info', 'contractor_specializations', 'contractor_status', 'created', 'cro', 'date_of_birth', 'email', + 'financial_info', 'first_name', 'gender', 'id', @@ -63,29 +55,55 @@ class UserSerializer(ModelSerializer): 'last_name', 'last_time_visit', 'location', - 'username', 'patronym', 'skype', + 'username', 'website', ) - - # read_only_fields = ( - # 'is_active', - # 'is_admin', - # ) + + def get__type(self, obj): + return 'User' + + # def create(self, validated_data): + # return User.objects.create(**validated_data) + + # def update(self, inst, validated_data): + # inst.email = validated_data.get('email', inst.email) + # inst.first_name = validated_data.get('first_name', inst.first_name) + # inst.is_active = validated_data.get('is_active', inst.is_active) + # inst.last_name = validated_data.get('last_name', inst.last_name) + # # inst.projects = validated_data.get('projects', inst.projects) + # + # inst.save() + # + # return inst - # def create(self, validated_data): - # return User.objects.create(**validated_data) - # def update(self, inst, validated_data): - # inst.email = validated_data.get('email', inst.email) - # inst.first_name = validated_data.get('first_name', inst.first_name) - # inst.is_active = validated_data.get('is_active', inst.is_active) - # inst.last_name = validated_data.get('last_name', inst.last_name) - # # inst.projects = validated_data.get('projects', inst.projects) - # - # inst.save() - # - # return inst +class TeamSerializer(ModelSerializer): + _type = SerializerMethodField() # Distinguish when used with generic serializers + avatar = ImageField() + contractors = UserSerializer(many=True) + owner = UserSerializer() + specializations = SpecializationSerializer(many=True) + # answers = AnswerSerializer(many=True) + + class Meta: + model = Team + + fields = ( + '_type', + 'answers', + 'avatar', + 'contractors', + 'created', + 'id', + 'name', + 'owner', + 'specializations', + ) + + def get__type(self, obj): + return 'Team' + # import code; code.interact(local=dict(globals(), **locals()))