diff --git a/archilance/util.py b/archilance/util.py index adbd3a1..80b72a4 100644 --- a/archilance/util.py +++ b/archilance/util.py @@ -65,8 +65,8 @@ def model_fields(model, width=200): pprint([( f.name, 'Relation? %s' % f.is_relation, - 'Null? %s' % f.null, - 'Blank? %s' % f.blank if not f.is_relation else '(relation)', + 'Null? %s' % getattr(f, 'null', None), + 'Blank? %s' % getattr(f, 'blank', None), ) for f in fields], width=width) diff --git a/projects/forms.py b/projects/forms.py index a6a1222..a94c7cd 100644 --- a/projects/forms.py +++ b/projects/forms.py @@ -136,8 +136,8 @@ class RealtyForm(forms.ModelForm): ) widgets = { - 'construction_type': forms.Select(attrs={'class':'selectpicker'}), - 'building_classification': forms.Select(attrs={'class':'selectpicker'}), + 'construction_type': forms.Select(attrs={'class': 'selectpicker'}), + 'building_classification': forms.Select(attrs={'class': 'selectpicker'}), } def __init__(self, *args, **kwargs): @@ -158,19 +158,13 @@ class PortfolioForm(forms.ModelForm): fields = '__all__' widgets = { - 'construction_type': forms.Select(attrs={'class':'selectpicker'}), - 'building_classification': forms.Select(attrs={'class':'selectpicker'}), - 'currency': forms.Select(attrs={'class':'selectpicker'}), - 'term_type': forms.Select(attrs={'class':'selectpicker'}), + 'construction_type': forms.Select(attrs={'class': 'selectpicker'}), + 'building_classification': forms.Select(attrs={'class': 'selectpicker'}), + 'currency': forms.Select(attrs={'class': 'selectpicker'}), + 'term_type': forms.Select(attrs={'class': 'selectpicker'}), } class ContractorProjectAnswerForm(forms.ModelForm): - # def __init__(self, *args, **kwargs): - # # import code; code.interact(local=dict(globals(), **locals())) - # self.project_id = kwargs.pop('project_id') - # super().__init__(*args, **kwargs) - # self.fields["project"].initial = self.project_id - class Meta: model = Answer @@ -183,8 +177,8 @@ class ContractorProjectAnswerForm(forms.ModelForm): ) widgets = { - 'currency': forms.Select(attrs={'class':'selectpicker'}), - 'term_type': forms.Select(attrs={'class':'selectpicker'}), + 'currency': forms.Select(attrs={'class': 'selectpicker'}), + 'term_type': forms.Select(attrs={'class': 'selectpicker'}), } diff --git a/projects/migrations/0009_auto_20160802_1414.py b/projects/migrations/0009_auto_20160802_1414.py new file mode 100644 index 0000000..e5c8983 --- /dev/null +++ b/projects/migrations/0009_auto_20160802_1414.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-02 11:14 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('projects', '0008_merge'), + ] + + operations = [ + migrations.AlterModelOptions( + name='answer', + options={'ordering': ('-created',), 'verbose_name': 'Отклик на проект', 'verbose_name_plural': 'Отклики на проекты'}, + ), + migrations.RemoveField( + model_name='answer', + name='contractor', + ), + migrations.AddField( + model_name='answer', + name='content_type', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType'), + preserve_default=False, + ), + migrations.AddField( + model_name='answer', + name='object_id', + field=models.IntegerField(default=None), + preserve_default=False, + ), + migrations.AlterField( + model_name='stage', + name='created', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/projects/migrations/0010_answerfiles.py b/projects/migrations/0010_answerfiles.py new file mode 100644 index 0000000..db3a9d4 --- /dev/null +++ b/projects/migrations/0010_answerfiles.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-02 13:34 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0009_auto_20160802_1414'), + ] + + operations = [ + migrations.CreateModel( + name='AnswerFiles', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('file', models.FileField(upload_to='projects/answer_files')), + ('answer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='files', to='projects.Answer')), + ], + options={ + 'verbose_name_plural': 'Файлы для откликов', + 'verbose_name': 'Файл для отклика', + }, + ), + ] diff --git a/projects/migrations/0011_auto_20160802_1653.py b/projects/migrations/0011_auto_20160802_1653.py new file mode 100644 index 0000000..a2ea21e --- /dev/null +++ b/projects/migrations/0011_auto_20160802_1653.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-02 13:53 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0010_answerfiles'), + ] + + operations = [ + migrations.AddField( + model_name='answer', + name='portfolios', + field=models.ManyToManyField(blank=True, related_name='answers', to='projects.Portfolio'), + ), + migrations.AddField( + model_name='answer', + name='secure_deal_only', + field=models.BooleanField(default=False), + ), + ] diff --git a/projects/models.py b/projects/models.py index a296928..44159b5 100644 --- a/projects/models.py +++ b/projects/models.py @@ -1,7 +1,9 @@ -from mptt.models import TreeForeignKey -from datetime import datetime +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.models import ContentType from django.db import models +from django.db.models import Q from django.utils import timezone +from mptt.models import TreeForeignKey from users.models import User, Team from specializations.models import Specialization @@ -117,23 +119,41 @@ class ProjectFile(models.Model): class Answer(models.Model): budget = models.DecimalField(max_digits=10, decimal_places=0) - contractor = models.ForeignKey(User, related_name='answers') created = models.DateTimeField(default=timezone.now) currency = models.CharField(max_length=5, choices=CURRENCIES, default='rur') + 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) term_type = models.CharField(max_length=10, choices=TERMS, default='hour') text = models.TextField() + content_type = models.ForeignKey(ContentType, limit_choices_to=Q(app_label='users', model='user') | Q(app_label='users', model='team')) + object_id = models.IntegerField() + author = GenericForeignKey('content_type', 'object_id') + def __str__(self): return self.text class Meta: - verbose_name = 'Ответ к проекту' - verbose_name_plural = 'Ответы к проектам' + verbose_name = 'Отклик на проект' + verbose_name_plural = 'Отклики на проекты' ordering = ('-created',) +class AnswerFiles(models.Model): + answer = models.ForeignKey(Answer, related_name='files', blank=True, null=True) + name = models.CharField(max_length=255) + file = models.FileField(upload_to='projects/answer_files') + + class Meta: + verbose_name = 'Файл для отклика' + verbose_name_plural = 'Файлы для откликов' + + def __str__(self): + return self.file and self.file.url or self.pk + + class Order(models.Model): contractor = models.ForeignKey(User, null=True, blank=True, related_name='orders') created = models.DateTimeField(default=timezone.now) diff --git a/projects/templates/customer_project_detail.html b/projects/templates/customer_project_detail.html deleted file mode 100644 index 481dce8..0000000 --- a/projects/templates/customer_project_detail.html +++ /dev/null @@ -1,215 +0,0 @@ -{% extends 'partials/base.html' %} - -{% block content %} - {% include 'partials/header.html' %} - {% load staticfiles %} - {% load humanize %} -
{{ project }}
-
- - {{ project.contractor.get_full_name }} [ivanov_petr] -
- -- Специализации: -
-Есть допуск СРО
-- {{ project.text }} -
-Исполнители
-Сравнить кандидатов
-Новые исполнители
-Есть допуск СРО
-Цена: - {{ answer.cost| intcomma }} - -
-- Срок: {{ answer.term }} {{ answer.term_type }} -
-Опубликован: {{ answer.created }}
-#} -{# Иванов Петр Иванович#} -{#
#} -{# #} -{# 13.0.2016 / 21:05#} -{# #} -{#Lorem ipsum dolor sit amet
#} -{#{{ project }}
+{{ project.name }}
{{ project.budget|intcomma }}
-{{ project.budget|intcomma }}
+
+ {% if project.customer.avatar %}
+
+ {% endif %}
- {{ project.customer.get_full_name }} [{{ project.customer }}] + {{ project.customer.get_full_name }} [{{ project.customer.username }}]
+ + {% if not request.user.is_contractor %} +@@ -56,24 +81,28 @@
Есть допуск СРО
-Есть допуск СРО
+