diff --git a/archilance/management/commands/generate_portfolios.py b/archilance/management/commands/generate_portfolios.py new file mode 100644 index 0000000..c50b957 --- /dev/null +++ b/archilance/management/commands/generate_portfolios.py @@ -0,0 +1,71 @@ +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 Portfolio, PortfolioPhoto, CURRENCIES, TERMS, BuildingClassfication , ConstructionType +from specializations.models import Specialization +from users.models import User, Team, GENDERS + + +class Command(BaseCommand): + def handle(self, *args, **options): + print('---------------------------------------') + print('Generating portfolios...') + print('---------------------------------------') + + + # ('photos', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), + # ('budget', 'Relation? False', 'Null? True', 'Blank? True', 'Hidden? False'), + # ('building_classification', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), + # ('construction_type', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), + # ('currency', 'Relation? False', 'Null? True', 'Blank? True', 'Hidden? False'), + # ('description', 'Relation? False', 'Null? False', 'Blank? False', 'Hidden? False'), + # ('location', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), + # ('name', 'Relation? False', 'Null? False', 'Blank? False', 'Hidden? False'), + # ('specialization', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), + # ('team', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), + # ('term', 'Relation? False', 'Null? True', 'Blank? True', 'Hidden? False'), + # ('term_type', 'Relation? False', 'Null? True', 'Blank? True', 'Hidden? False'), + # ('user', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), + # ('worksell', 'Relation? False', 'Null? False', 'Blank? True', 'Hidden? False'), + + + def create_portfolio(i): + portf = Portfolio( + name='Portforlio %s' % i, + description="Portforlio %s's description" % i, + budget=util.random_amount(), + currency=_.sample(CURRENCIES)[0], + term=_.random(0, 20), + term_type=_.sample(TERMS)[0], + worksell=_.sample((True, False)), + ) + + portf.save() + + if _.sample((True, False)): + portf.user = User.contractor_objects.order_by('?').first() + else: + portf.team = Team.objects.order_by('?').first() + + portf.building_classification = BuildingClassfication.objects.order_by('?').first() + portf.construction_type = ConstructionType.objects.order_by('?').first() + portf.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() + portf.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_: portf.photos.create(img='_sample_files/%s' % util.take_one_random(pic_names)), + _.random(1, 15), + ) + + portf.save() + return portf + + _.times(create_portfolio, 1000) diff --git a/archilance/management/commands/generate_teams.py b/archilance/management/commands/generate_teams.py index 52a9cf1..00cc366 100644 --- a/archilance/management/commands/generate_teams.py +++ b/archilance/management/commands/generate_teams.py @@ -18,15 +18,12 @@ class Command(BaseCommand): print('---------------------------------------') + # ('portfolios', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), # ('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'), + # ('specializations', '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)] + pass diff --git a/archilance/management/commands/generate_users.py b/archilance/management/commands/generate_users.py index 50963e8..425299b 100644 --- a/archilance/management/commands/generate_users.py +++ b/archilance/management/commands/generate_users.py @@ -95,7 +95,7 @@ class Command(BaseCommand): for user in users: user.set_password('123') user.groups.add(customer_group if user.pk % 2 == 0 else contractor_group) - user.contractor_specializations = Specialization.objects.order_by('?')[:_.random(1, 5)] + user.contractor_specializations = Specialization.objects.root_nodes()[0].get_descendants().order_by('?')[:_.random(1, 5)] user.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() user.save() diff --git a/archilance/management/commands/tmp.py b/archilance/management/commands/tmp.py index fcda9a3..751c975 100644 --- a/archilance/management/commands/tmp.py +++ b/archilance/management/commands/tmp.py @@ -8,13 +8,21 @@ import random from archilance import util from common.models import Location from projects.models import Project, Order, CURRENCIES, TERMS, Specialization, Realty -from users.models import User +from users.models import User, Team class Command(BaseCommand): def handle(self, *args, **options): - for user in User.objects.all(): - user.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() - user.cro = _.sample((True, False)) + # for user in User.objects.all(): + # user.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() + # user.cro = _.sample((True, False)) + # + # user.save() + + #------------------------------------------ + + for team in Team.objects.all(): + # team.specializations = Specialization.objects.root_nodes()[0].get_descendants().order_by('?')[:_.random(1, 5)] + team.created = util.random_date() - user.save() + team.save() diff --git a/common/migrations/0005_auto_20160720_1327.py b/common/migrations/0005_auto_20160720_1327.py new file mode 100644 index 0000000..67d99fa --- /dev/null +++ b/common/migrations/0005_auto_20160720_1327.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-20 10:27 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0004_settings'), + ] + + operations = [ + migrations.AlterModelOptions( + name='settings', + options={'verbose_name': 'Настройки сайта', 'verbose_name_plural': 'Настройки сайта'}, + ), + ] diff --git a/projects/migrations/0040_portfolio_team.py b/projects/migrations/0040_portfolio_team.py new file mode 100644 index 0000000..e16e0be --- /dev/null +++ b/projects/migrations/0040_portfolio_team.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-20 10:27 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0021_contractorresumefiles_resume'), + ('projects', '0039_auto_20160707_1724'), + ] + + operations = [ + migrations.AddField( + model_name='portfolio', + name='team', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='portfolios', to='users.Team'), + preserve_default=False, + ), + ] diff --git a/projects/migrations/0041_auto_20160720_1531.py b/projects/migrations/0041_auto_20160720_1531.py new file mode 100644 index 0000000..3361a16 --- /dev/null +++ b/projects/migrations/0041_auto_20160720_1531.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-20 12:31 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0040_portfolio_team'), + ] + + operations = [ + migrations.AlterField( + model_name='portfolio', + name='team', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='portfolios', to='users.Team'), + ), + migrations.AlterField( + model_name='portfolio', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='portfolios', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/projects/migrations/0042_auto_20160720_1641.py b/projects/migrations/0042_auto_20160720_1641.py new file mode 100644 index 0000000..fc44a91 --- /dev/null +++ b/projects/migrations/0042_auto_20160720_1641.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-20 13:41 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0041_auto_20160720_1531'), + ] + + operations = [ + migrations.AlterField( + model_name='portfoliophoto', + name='portfolio', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='projects.Portfolio'), + ), + ] diff --git a/projects/models.py b/projects/models.py index d9935b4..df4edcd 100644 --- a/projects/models.py +++ b/projects/models.py @@ -3,7 +3,7 @@ from datetime import datetime from django.db import models from django.utils import timezone -from users.models import User +from users.models import User, Team from specializations.models import Specialization @@ -181,16 +181,17 @@ class Candidate(models.Model): 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) + building_classification = models.ForeignKey(BuildingClassfication, related_name='portfolios', null=True, blank=True) + construction_type = models.ForeignKey(ConstructionType, related_name='portfolios', null=True, blank=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) name = models.CharField(max_length=255) - specialization = TreeForeignKey(Specialization, related_name='portfolios',null=True, blank=True) - term = models.IntegerField(default=0,null=True, blank=True) - term_type = models.CharField(max_length=20, choices=TERMS, default='hour',null=True, blank=True) - user = models.ForeignKey(User, related_name='portfolios') + specialization = TreeForeignKey(Specialization, related_name='portfolios', null=True, blank=True) + team = models.ForeignKey(Team, related_name='portfolios', null=True, blank=True) + term = models.IntegerField(default=0, null=True, blank=True) + term_type = models.CharField(max_length=20, choices=TERMS, default='hour', null=True, blank=True) + user = models.ForeignKey(User, related_name='portfolios', null=True, blank=True) worksell = models.BooleanField(default=False) def __str__(self): @@ -201,20 +202,17 @@ class Portfolio(models.Model): verbose_name_plural = 'Портфолио' def get_cover(self): - cover = None - all_photos = self.portfoliophoto_set.all() - if all_photos: - cover = all_photos[0].img - return cover + photo = self.photos.first() + return photo and photo.img.url class PortfolioPhoto(models.Model): img = models.ImageField(upload_to='projects/portfolio') - portfolio = models.ForeignKey(Portfolio) - + portfolio = models.ForeignKey(Portfolio, related_name='photos') + class Meta: verbose_name = 'Фото портфолио' verbose_name_plural = 'Фото портфолио' - - # def __str__(self): - # return self.img + + def __str__(self): + return self.img and self.img.url or str(self.img) diff --git a/projects/templates/project_filter.html b/projects/templates/project_filter.html index af9148e..f8231f2 100644 --- a/projects/templates/project_filter.html +++ b/projects/templates/project_filter.html @@ -13,7 +13,7 @@
-
+ --
diff --git a/users/forms.py b/users/forms.py index 31e790f..7e4a644 100644 --- a/users/forms.py +++ b/users/forms.py @@ -41,11 +41,14 @@ class UserEditForm(ModelForm): class ContractorFilterForm(forms.Form): - CONTRACTOR_ORDER_CHOICES = ( # "Упорядочить по"... - ('name', 'названию'), - ('budget', 'цене'), - ('created', 'дате размещения'), - ('views', 'просмотрам'), + CONTRACTOR_ORDER_CHOICES = ( + ('', 'Сортировать по...'), + ('name', 'Названию'), + ('created', 'Дате размещения'), + ('views', 'Просмотрам'), + ('reviews', 'Отзывам'), + ('rating', 'Рейтингу'), + # ('project_number', 'Кол-ву выполн. проектов'), ) PARTY_TYPES = ( diff --git a/users/migrations/0022_team_specializations.py b/users/migrations/0022_team_specializations.py new file mode 100644 index 0000000..12fdf51 --- /dev/null +++ b/users/migrations/0022_team_specializations.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-20 10:27 +from __future__ import unicode_literals + +from django.db import migrations +import mptt.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('specializations', '0002_auto_20160602_1203'), + ('users', '0021_contractorresumefiles_resume'), + ] + + operations = [ + migrations.AddField( + model_name='team', + name='specializations', + field=mptt.fields.TreeManyToManyField(blank=True, related_name='teams', to='specializations.Specialization'), + ), + ] diff --git a/users/migrations/0023_team_created.py b/users/migrations/0023_team_created.py new file mode 100644 index 0000000..c895a18 --- /dev/null +++ b/users/migrations/0023_team_created.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-20 16:30 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0022_team_specializations'), + ] + + operations = [ + migrations.AddField( + model_name='team', + name='created', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/users/models.py b/users/models.py index f70e21f..620c8d1 100644 --- a/users/models.py +++ b/users/models.py @@ -179,10 +179,11 @@ class User(AbstractBaseUser, PermissionsMixin): class Team(models.Model): + created = models.DateTimeField(default=timezone.now) name = models.CharField(max_length=255) owner = models.OneToOneField(User, related_name='team', blank=True, null=True) + specializations = TreeManyToManyField(Specialization, related_name='teams', blank=True) users = models.ManyToManyField(User, related_name ='teams', blank=True) - # groups = models.ManyToManyField(Group, related_name='teams', blank=True) def __str__(self): return self.name diff --git a/users/templates/contractor_filter.html b/users/templates/contractor_filter.html index 156c7eb..0eded61 100644 --- a/users/templates/contractor_filter.html +++ b/users/templates/contractor_filter.html @@ -152,12 +152,15 @@
- + {% for val, text in form.order_by.field.choices %} + + {% endfor %} -
+
+ + +
@@ -174,47 +177,134 @@

{{ team.name }}

+ +
Свободен
+
+ + +
+ +
+ + +
+
+

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

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

Specializations: {{ team.owner.contractor_specializations.all }}

Location: {{ team.owner.location }}

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

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

CRO: {{ team.owner.cro }}

Work types: {% for o in team.owner.orders.all %}{{ o.project.work_type }}, {% endfor %}



######## Team users #########

Specializations: {% for u in team.users.all %}{{ u.contractor_specializations.all }}, {% endfor %}

Location: {% for u in team.users.all %}{{ u.location }}, {% endfor %}

Build. classif-s: {% for u in team.users.all %}{% for o in u.orders.all %}{{ o.project.realty.building_classification }}, {% endfor %}; {% endfor %}

Constr. types: {% for u in team.users.all %}{% for o in u.orders.all %}{{ o.project.realty.construction_type }}, {% endfor %}; {% endfor %}

CRO: {% for u in team.users.all %}{{ u.cro }}, {% endfor %}

Work types: {% for u in team.users.all %}{% for o in u.orders.all %}{{ o.project.work_type }}, {% endfor %}; {% endfor %}
+
+ +
+
+

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

- {% endif %} +
+ +{# {% if TEMPLATE_DEBUG %}#} +{#
#} +{#
######## Team owner #########

Specializations: {{ team.owner.contractor_specializations.all }}

Location: {{ team.owner.location }}

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

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

CRO: {{ team.owner.cro }}

Work types: {% for o in team.owner.orders.all %}{{ o.project.work_type }}, {% endfor %}



######## Team users #########

Specializations: {% for u in team.users.all %}{{ u.contractor_specializations.all }}, {% endfor %}

Location: {% for u in team.users.all %}{{ u.location }}, {% endfor %}

Build. classif-s: {% for u in team.users.all %}{% for o in u.orders.all %}{{ o.project.realty.building_classification }}, {% endfor %}; {% endfor %}

Constr. types: {% for u in team.users.all %}{% for o in u.orders.all %}{{ o.project.realty.construction_type }}, {% endfor %}; {% endfor %}

CRO: {% for u in team.users.all %}{{ u.cro }}, {% endfor %}

Work types: {% for u in team.users.all %}{% for o in u.orders.all %}{{ o.project.work_type }}, {% endfor %}; {% endfor %}
#} +{#
#} +{# {% endif %}#} +
+ {% for portf in team.portfolios.all|slice:':4' %} + + {% endfor %}
{% endwith %} @@ -236,7 +326,7 @@
- {% 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 %} - +{# {% 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 %}#}
- - - -
{% endwith %} diff --git a/users/templates/contractor_profile.html b/users/templates/contractor_profile.html index fbc1a65..547575f 100644 --- a/users/templates/contractor_profile.html +++ b/users/templates/contractor_profile.html @@ -141,7 +141,7 @@
+ style="background:rgba(0, 0, 0, 0) url('{{ p.get_cover }}') no-repeat scroll center center / cover ;">
diff --git a/users/views.py b/users/views.py index 81ce27b..ad1a527 100644 --- a/users/views.py +++ b/users/views.py @@ -178,8 +178,8 @@ class ContractorFilterView(BaseMixin, View): if ord: if ord == 'name': coll = natsort.natsorted(coll, key=lambda obj: getattr(obj, 'username', None) or obj.name, reverse=reverse_order) - else: - coll = natsort.natsorted(coll, key=lambda obj: getattr(obj, ord), reverse=reverse_order) + elif ord =='created': + coll = natsort.natsorted(coll, key=lambda obj: obj.created, reverse=reverse_order) context.update({ 'last_order_by': last_order_by,