diff --git a/archilance/management/commands/generate_teams.py b/archilance/management/commands/generate_teams.py new file mode 100644 index 0000000..52a9cf1 --- /dev/null +++ b/archilance/management/commands/generate_teams.py @@ -0,0 +1,32 @@ +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 specializations.models import Specialization +from users.models import User, GENDERS, Team + + +class Command(BaseCommand): + def handle(self, *args, **options): + print('---------------------------------------') + print('Generating teams...') + print('---------------------------------------') + + + # ('owner', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), + # ('users', 'Relation? True', 'Null? False', '(relation)', 'Hidden? False'), + # + # ('name', 'Relation? False', 'Null? False', 'Blank? False', 'Hidden? False'), + + + contractors = User.contractor_objects.order_by('?') + contractors = contractors[:contractors.count() // 2] + + for contr in contractors: + team = Team.objects.create(name="%s's team" % contr.username, owner=contr) + team.users = User.contractor_objects.filter(team=None)[:_.random(1, 4)] diff --git a/archilance/settings/base.py b/archilance/settings/base.py index 572c777..9cb8382 100644 --- a/archilance/settings/base.py +++ b/archilance/settings/base.py @@ -248,6 +248,7 @@ EMAIL_DEFAULT = 'noreply@archilance.ru' SHELL_PLUS_POST_IMPORTS = ( # Extra auto imports + 'natsort', ('archilance', 'util'), ('pprint', ('pprint', 'pformat')), ) diff --git a/requirements/base.txt b/requirements/base.txt index 61a9ced..790f1a6 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -36,7 +36,4 @@ six==1.10.0 sorl-thumbnail==12.3 sqlparse==0.1.19 tornado==4.3 - - - - +natsort diff --git a/users/forms.py b/users/forms.py index 9970216..8dde601 100644 --- a/users/forms.py +++ b/users/forms.py @@ -47,7 +47,13 @@ class ContractorFilterForm(forms.Form): # ('created', 'дате размещения'), # ('views', 'просмотрам'), # ) - # + + PARTY_TYPES = ( + ('', 'Все'), + ('teams', 'Группы'), + ('contractors', 'Исполнители'), + ) + # order_by = forms.ChoiceField(required=False, choices=PROJECT_ORDER_CHOICES) # last_order_by = forms.ChoiceField(required=False, choices=PROJECT_ORDER_CHOICES) # reverse_order = forms.BooleanField(required=False) @@ -84,6 +90,11 @@ class ContractorFilterForm(forms.Form): cro = forms.BooleanField(required=False) + party_types = forms.ChoiceField( + choices=PARTY_TYPES, + required=False, + ) + def __init__(self, *args, **kwargs): self.request = kwargs.pop('request') super().__init__(*args, **kwargs) diff --git a/users/models.py b/users/models.py index 2e51b55..f70e21f 100644 --- a/users/models.py +++ b/users/models.py @@ -15,7 +15,6 @@ GENDERS = ( class UserManager(BaseUserManager): def create_user(self, username, email, password=None, **kwargs): - # import code; code.interact(local=dict(globals(), **locals())) if not email: raise ValueError('Users must have an email address') @@ -77,6 +76,7 @@ class ContractorFinancialInfo(models.Model): verbose_name = 'Финансовая информация' verbose_name_plural = 'Финансовая информация' + class ContractorResume(models.Model): resume_file = models.FileField(upload_to='users/resume/files/') text = models.TextField() diff --git a/users/templates/contractor_filter.html b/users/templates/contractor_filter.html index 2c20381..84a02ac 100644 --- a/users/templates/contractor_filter.html +++ b/users/templates/contractor_filter.html @@ -137,9 +137,15 @@
- - - + {% for val, text in form.party_types.field.choices %} + + {% endfor %}
@@ -155,154 +161,158 @@ - {% for contractor in contractors %} -
-
-
- execitor-image -
-

- {{ contractor.get_full_name }} [{{ contractor.username }}] -

- -
Свободен
-
- - - - - -
-
-

- Специализации: -

-
- Интерьеры - 2-й -
-
- Визуализация/3D - 45-й -
-
- Экстерьеры - 10-й -
-
-
- Архитектура - 3-й -
-
- 3D Моделирование - 100-й -
-
- -
-
- - -
- -
-
-

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

-
-
- - - {% if TEMPLATE_DEBUG %} -
-
Specializations: {{ contractor.contractor_specializations.all }}

Location: {{ contractor.location }}

Build. classif-s: {% for o in contractor.orders.all %}{{ o.project.realty.building_classification }}, {% endfor %}

Constr. types: {% for o in contractor.orders.all %}{{ o.project.realty.construction_type }}, {% endfor %}

CRO: {{ contractor.cro }}

Work types: {% for o in contractor.orders.all %}{{ o.project.work_type }}, {% endfor %}
-
- {% endif %} - - - -
- {% endfor %} +{# {% for contractor in contractors %}#} +{#
#} +{#
#} +{#
#} +{# execitor-image#} +{#
#} +{#

#} +{# {{ contractor.get_full_name }} [{{ contractor.username }}]#} +{#

#} +{# #} +{#
Свободен
#} +{#
#} +{# #} +{# #} +{# #} +{# #} +{# #} +{#
#} +{#
#} +{#

#} +{# Специализации:#} +{#

#} +{#
#} +{# Интерьеры#} +{# 2-й#} +{#
#} +{#
#} +{# Визуализация/3D#} +{# 45-й#} +{#
#} +{#
#} +{# Экстерьеры#} +{# 10-й#} +{#
#} +{#
#} +{#
#} +{# Архитектура#} +{# 3-й#} +{#
#} +{#
#} +{# 3D Моделирование#} +{# 100-й#} +{#
#} +{#
#} +{# #} +{#
#} +{#
#} +{# #} +{# #} +{#
#} +{# #} +{#
#} +{#
#} +{#

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

#} +{#
#} +{#
#} +{# #} +{# #} +{# {% if TEMPLATE_DEBUG %}#} +{#
#} +{#
Specializations: {{ contractor.contractor_specializations.all }}

Location: {{ contractor.location }}

Build. classif-s: {% for o in contractor.orders.all %}{{ o.project.realty.building_classification }}, {% endfor %}

Constr. types: {% for o in contractor.orders.all %}{{ o.project.realty.construction_type }}, {% endfor %}

CRO: {{ contractor.cro }}

Work types: {% for o in contractor.orders.all %}{{ o.project.work_type }}, {% endfor %}
#} +{#
#} +{# {% endif %}#} +{# #} +{# #} +{# #} +{#
#} +{# {% endfor %}#} + {% for obj in coll %} +{# Get the type of an object, like `if type(obj) == Team: ...`#} +
{{ obj }}
+ {% endfor %}
diff --git a/users/views.py b/users/views.py index 537beb3..f53e4b2 100644 --- a/users/views.py +++ b/users/views.py @@ -8,11 +8,13 @@ from django.http import HttpResponse from django.shortcuts import render, get_object_or_404, redirect from django.views.generic import ListView, DetailView, View, UpdateView, CreateView from pprint import pprint, pformat +import itertools +import natsort import pydash as _; _.map = _.map_; _.filter = _.filter_ from .forms import UserEditForm, ContractorFilterForm, ContractorFinancicalInfoForm from .mixins import CheckForUserMixin -from .models import User, ContractorFinancialInfo +from .models import User, Team, ContractorFinancialInfo from archilance.mixins import BaseMixin from common.utils import get_or_none from projects.forms import PortfolioForm @@ -38,8 +40,7 @@ class ContractorFilterView(BaseMixin, View): def get(self, request, *args, **kwargs): form = self.form_class(request.GET, request=request) context = self.get_context_data(**_.merge({}, request.GET, kwargs)) - - contractors = User.contractor_objects + contractors = teams = None if form.is_valid(): cro = form.cleaned_data.get('cro') @@ -48,56 +49,53 @@ class ContractorFilterView(BaseMixin, View): work_type = form.cleaned_data.get('work_type') build_classif = form.cleaned_data.get('building_classification') constr_type = form.cleaned_data.get('construction_type') + party_types = form.cleaned_data.get('party_types') - contractors = contractors.filter(cro=cro) - - if specialization: - contractors = contractors.filter( - # specialization__lft__gte=specialization.lft, - # specialization__rght__lte=specialization.rght, - - contractor_specializations=specialization, # TODO: Honor the hierarchical data structure - ) - - if location: - contractors = contractors.filter( - location__lft__gte=location.lft, - location__rght__lte=location.rght, - ) + get_contractors = get_teams = None - if work_type: - contractors = contractors.filter(orders__project__work_type=work_type).distinct() # TODO: OK? + if not party_types: + get_contractors = get_teams = True + elif party_types == 'contractors': + get_contractors = True + elif party_types == 'teams': + get_teams = True - if build_classif: - contractors = contractors.filter(orders__project__realty__building_classification=build_classif) - - if constr_type: - contractors = contractors.filter(orders__project__realty__construction_type=constr_type) - - # import code; code.interact(local=dict(globals(), **locals())) + if get_contractors: + contractors = User.contractor_objects.filter(cro=cro) + + if specialization: + contractors = contractors.filter( + # specialization__lft__gte=specialization.lft, + # specialization__rght__lte=specialization.rght, + + contractor_specializations=specialization, # TODO: Honor the hierarchical data structure + ) + + if location: + contractors = contractors.filter( + location__lft__gte=location.lft, + location__rght__lte=location.rght, + ) + + if work_type: + contractors = contractors.filter(orders__project__work_type=work_type).distinct() # TODO: OK? + + if build_classif: + contractors = contractors.filter(orders__project__realty__building_classification=build_classif) + + if constr_type: + contractors = contractors.filter(orders__project__realty__construction_type=constr_type) + + # contr_count = contractors.count() + # display_msg = 'Найдено %s исполнителей' % contr_count if contr_count > 0 else 'Ничего не найдено' - # order_by = form.cleaned_data.get('order_by') - # last_order_by = form.cleaned_data.get('last_order_by') - # reverse_order = form.cleaned_data.get('reverse_order') - # - # if order_by: - # if order_by == last_order_by: - # reverse_order = not reverse_order - # else: - # reverse_order = False - # - # projects = projects.order_by('-%s' % order_by if reverse_order else order_by) - # last_order_by = order_by - # elif last_order_by: - # projects = projects.order_by('-%s' % last_order_by if reverse_order else last_order_by) - # - # context.update({ - # 'last_order_by': last_order_by, - # 'reverse_order': reverse_order, - # }) + if get_teams: + teams = Team.objects.all() + + # team_count = teams.count() + # display_msg = 'Найдено %s команд' % team_count if team_count > 0 else 'Ничего не найдено' - contr_count = contractors.count() - display_msg = 'Найдено %s исполнителей' % contr_count if contr_count > 0 else 'Ничего не найдено' + display_msg = 'Результаты поиска' else: display_msg = 'Пожалуйста, введите корректные данные' @@ -107,22 +105,24 @@ class ContractorFilterView(BaseMixin, View): '
{form}
' ).format(form=pformat(form.errors))) + coll = tuple(itertools.chain(contractors, teams)) + coll = natsort.natsorted(coll, key=lambda obj: getattr(obj, 'username', None) or getattr(obj, 'name')) - paginator = Paginator(contractors.all(), settings.PAGE_SIZE) + paginator = Paginator(coll, settings.PAGE_SIZE) page = request.GET.get('page') try: - contractors = paginator.page(page) + coll = paginator.page(page) except PageNotAnInteger: - contractors = paginator.page(1) + coll = paginator.page(1) except EmptyPage: - contractors = paginator.page(paginator.num_pages) + coll = paginator.page(paginator.num_pages) context.update({ 'form': form, - 'contractors': contractors, + 'coll': coll, 'is_paginated': True, - 'page_obj': contractors, + 'page_obj': coll, 'display_msg': display_msg, })