diff --git a/archilance/mixins.py b/archilance/mixins.py index 94ed526..78f1930 100644 --- a/archilance/mixins.py +++ b/archilance/mixins.py @@ -4,16 +4,17 @@ from django.views.generic.base import ContextMixin class BaseMixin(ContextMixin): def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) + c = super().get_context_data(**kwargs) - pk = self.kwargs.get('pk') + pk = self.kwargs.get('pk') # Current object's ID + next = self.kwargs.get('next') # Redirect back path - if pk: - context['pk'] = pk + if pk: c['pk'] = pk + if next: c['next'] = next - context['domain'] = Site.objects.get_current().domain + c['domain'] = Site.objects.get_current().domain - return context + return c # import code; code.interact(local=dict(globals(), **locals())) diff --git a/archilance/wsgi.py b/archilance/wsgi.py index 88be385..69856cf 100644 --- a/archilance/wsgi.py +++ b/archilance/wsgi.py @@ -7,10 +7,21 @@ For more information on this file, see https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ """ -import os - from django.core.wsgi import get_wsgi_application +from django.template.base import Variable +import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archilance.settings") application = get_wsgi_application() + + +# Patch template Variable to output empty string for None values: + +old_resolve_lookup = Variable._resolve_lookup + +def new_resolve_lookup(self, *args, **kwargs): + val = old_resolve_lookup(self, *args, **kwargs) + return '' if val == None else val + +Variable._resolve_lookup = new_resolve_lookup diff --git a/common/__init__.py b/common/__init__.py index e69de29..a06fd3d 100644 --- a/common/__init__.py +++ b/common/__init__.py @@ -0,0 +1 @@ +default_app_config = 'common.apps.CommonConfig' diff --git a/common/templates/templatetags/inspect.html b/common/templates/templatetags/inspect.html new file mode 100644 index 0000000..d723e04 --- /dev/null +++ b/common/templates/templatetags/inspect.html @@ -0,0 +1 @@ +
{{ obj }}
diff --git a/common/templatetags/common_tags.py b/common/templatetags/common_tags.py new file mode 100644 index 0000000..925aafe --- /dev/null +++ b/common/templatetags/common_tags.py @@ -0,0 +1,17 @@ +from django import template +from pprint import pprint, pformat + +register = template.Library() + + +@register.inclusion_tag('templatetags/inspect.html', takes_context=True) +def inspect(context, obj): + return { + 'obj': pformat(obj.__dict__), + } + +@register.inclusion_tag('templatetags/inspect.html', takes_context=True) +def inspect2(context, obj): + return { + 'obj': pformat(dir(obj)), + } diff --git a/projects/admin.py b/projects/admin.py index f9faa7a..4c73ff9 100644 --- a/projects/admin.py +++ b/projects/admin.py @@ -1,8 +1,18 @@ from django.contrib import admin -from .models import Project, Portfolio, PortfolioPhoto, \ - Answer, Realty, Candidate, Order, Stage,\ - BuildingClassfication, ConstructionType, ProjectFile +from .models import ( + Answer, + BuildingClassfication, + Candidate, + ConstructionType, + Order, + Portfolio, + PortfolioPhoto, + Project, + ProjectFile, + Realty, + Stage, +) class ProjectAdmin(admin.ModelAdmin): diff --git a/projects/forms.py b/projects/forms.py index 0779cdf..e807541 100644 --- a/projects/forms.py +++ b/projects/forms.py @@ -10,7 +10,12 @@ from users.models import User # RealtyFormSet = inlineformset_factory(Project, Realty) -class ProjectForm(ModelForm): + +class ProjectsForm(Form): + name = forms.CharField(max_length=255) + + +class CustomerProjectCreateForm(ModelForm): specialization = TreeNodeChoiceField(queryset=Specialization.objects.exclude(id=1)) class Meta: @@ -21,13 +26,13 @@ class ProjectForm(ModelForm): 'budget_by_agreement', 'cro', 'currency', + 'deal_type', 'name', 'price_and_term_required', - 'deal_type', + 'specialization', 'term_type', 'text', 'work_type', - 'specialization', ) widgets = { @@ -35,10 +40,10 @@ class ProjectForm(ModelForm): 'currency': Select(attrs={'class':'selectpicker2 valul'}), 'term_type': Select(attrs={'class':'selectpicker'}), } - - -class ProjectsForm(Form): - name = forms.CharField(max_length=255) + + def __init__(self, *args, **kwargs): + self.request = kwargs.pop('request') + super().__init__(*args, **kwargs) class RealtyForm(ModelForm): @@ -66,7 +71,7 @@ class PortfolioForm(ModelForm): fields = '__all__' -class AnswerForm(ModelForm): +class ContractorProjectAnswerForm(ModelForm): # def __init__(self, *args, **kwargs): # # import code; code.interact(local=dict(globals(), **locals())) # self.project_id = kwargs.pop('project_id') @@ -107,9 +112,13 @@ class StageForm(ModelForm): PortfolioPhotoFormSet = inlineformset_factory(Portfolio, PortfolioPhoto, fields=('img',)) -class ProjectTrashForm(Form): +class ProjectEditForm(forms.ModelForm): pk = forms.ModelChoiceField(queryset=Project.objects.none()) + class Meta: + model = Project + fields = '__all__' + def __init__(self, *args, **kwargs): self.req = kwargs.pop('req') super().__init__(*args, **kwargs) @@ -117,35 +126,31 @@ class ProjectTrashForm(Form): self.fields['pk'].queryset = self.req.user.projects.filter(state='active') -class ProjectRestoreForm(Form): +class ProjectTrashForm(Form): pk = forms.ModelChoiceField(queryset=Project.objects.none()) def __init__(self, *args, **kwargs): self.req = kwargs.pop('req') super().__init__(*args, **kwargs) - self.fields['pk'].queryset = self.req.user.projects.filter(state='trashed') + self.fields['pk'].queryset = self.req.user.projects.filter(state='active') -class ProjectDeleteForm(Form): +class ProjectRestoreForm(Form): pk = forms.ModelChoiceField(queryset=Project.objects.none()) def __init__(self, *args, **kwargs): self.req = kwargs.pop('req') super().__init__(*args, **kwargs) - self.fields['pk'].queryset = self.req.user.projects.filter(Q(state='active') | Q(state='trashed')) + self.fields['pk'].queryset = self.req.user.projects.filter(state='trashed') -class ProjectEditForm(forms.ModelForm): +class ProjectDeleteForm(Form): pk = forms.ModelChoiceField(queryset=Project.objects.none()) - class Meta: - model = Project - fields = '__all__' - def __init__(self, *args, **kwargs): self.req = kwargs.pop('req') super().__init__(*args, **kwargs) - self.fields['pk'].queryset = self.req.user.projects.filter(state='active') + self.fields['pk'].queryset = self.req.user.projects.filter(Q(state='active') | Q(state='trashed')) diff --git a/projects/templates/customer_project_create.html b/projects/templates/customer_project_create.html index de9c2a8..172b172 100644 --- a/projects/templates/customer_project_create.html +++ b/projects/templates/customer_project_create.html @@ -11,18 +11,18 @@
{% csrf_token %} - {{ form_project.errors }} + {{ form.errors }} {{ form_realty.errors }}

Формирование заказа

Название заказа

- +

Подробно опишите задание

- +
@@ -46,11 +46,11 @@

Тип работы:

- +

Проектирование

- +

Техническое сопровождение

@@ -69,7 +69,7 @@
- {{ form_project.specialization }} + {{ form.specialization }}
- {{ form_project.currency }} + + {{ form.currency }}
- {{ form_project.term_type }} + {{ form.term_type }}
+

или по договоренности

- +

Сделать для исполнителей обязательным для заполнения поля цена и срок

@@ -112,23 +112,21 @@
- +

Безопасная сделка (с резервированием бюджета) -

- Описание + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Porro vel suscipit eaque quidem voluptate aperiam enim aut libero, excepturi architecto maxime, placeat maiores, odio itaque, ex consectetur dignissimos dicta officia

- +

Прямая оплата Исполнителю на его кошелек/счет

- Описание + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Porro vel suscipit eaque quidem voluptate aperiam enim aut libero, excepturi architecto maxime, placeat maiores, odio itaque, ex consectetur dignissimos dicta officia

@@ -159,7 +157,7 @@
- +
{{ form_realty.building_classification }} @@ -179,7 +177,7 @@ {{ form_realty.city }}
- +

Требуется допуск СРО

@@ -187,9 +185,7 @@ - diff --git a/projects/templates/customer_project_detail.html b/projects/templates/customer_project_detail.html index ffe72ad..8c25c11 100644 --- a/projects/templates/customer_project_detail.html +++ b/projects/templates/customer_project_detail.html @@ -77,11 +77,11 @@

- + Редактировать - + {% csrf_token %} diff --git a/projects/templates/project_edit_test.html b/projects/templates/customer_project_edit_test.html similarity index 51% rename from projects/templates/project_edit_test.html rename to projects/templates/customer_project_edit_test.html index 28a1bc5..8b4c3df 100644 --- a/projects/templates/project_edit_test.html +++ b/projects/templates/customer_project_edit_test.html @@ -1,4 +1,5 @@ {% load staticfiles %} +{% load common_tags %} @@ -24,13 +25,42 @@

"pk": {{ pk }}

- + {% csrf_token %} {{ form.as_p }} + Назад + +
+ +
+
    + {% for id, name in form.deal_type.field.choices %} +
  • {{ id }} {% if id == form.deal_type.value %}(current){% endif %}
  • + +{#
    #} +{# #} +{# #} +{# #} +{#
    #} + {% endfor %} +
+ + + {% inspect form.deal_type.field %} + +
+ + {% inspect2 form.deal_type.field %} +
diff --git a/projects/templates/contractor_project_detail.html b/projects/templates/project_detail.html similarity index 97% rename from projects/templates/contractor_project_detail.html rename to projects/templates/project_detail.html index cd9c4c3..a041ee0 100644 --- a/projects/templates/contractor_project_detail.html +++ b/projects/templates/project_detail.html @@ -102,7 +102,8 @@
-
+ + {{ form.errors }} {% csrf_token %}
diff --git a/projects/templates/project_list.html b/projects/templates/project_list.html index 7c77181..9a91273 100644 --- a/projects/templates/project_list.html +++ b/projects/templates/project_list.html @@ -154,7 +154,7 @@

- {{ proj }} + {{ proj }}

  • diff --git a/projects/urls.py b/projects/urls.py index 67985ae..d9dec07 100644 --- a/projects/urls.py +++ b/projects/urls.py @@ -4,14 +4,15 @@ from django.views.generic import TemplateView from .views import ( add_candidate, ChatView, + ContractorProjectAnswerView, + CustomerProjectCreateView, + CustomerProjectDeleteView, + CustomerProjectEditView, + CustomerProjectRestoreView, + CustomerProjectTrashView, OfferOrderView, ProjectComparisonView, - ProjectCreateView, - ProjectDeleteView, - ProjectEditView, - ProjectRestoreView, ProjectsView, - ProjectTrashView, ProjectView, ) @@ -20,15 +21,16 @@ app_name = 'projects' urlpatterns = [ urls.url(r'^$', ProjectsView.as_view(), name='list'), + urls.url(r'^create/$', CustomerProjectCreateView.as_view(), name='customer-project-create'), urls.url(r'^(?P\d+)/$', ProjectView.as_view(), name='detail'), - urls.url(r'^(?P\d+)/trash/$', ProjectTrashView.as_view(), name='trash'), - urls.url(r'^(?P\d+)/restore/$', ProjectRestoreView.as_view(), name='restore'), - urls.url(r'^(?P\d+)/delete/$', ProjectDeleteView.as_view(), name='delete'), - urls.url(r'^(?P\d+)/edit/$', ProjectEditView.as_view(), name='edit'), + urls.url(r'^(?P\d+)/edit/$', CustomerProjectEditView.as_view(), name='customer-project-edit'), + urls.url(r'^(?P\d+)/trash/$', CustomerProjectTrashView.as_view(), name='customer-project-trash'), + urls.url(r'^(?P\d+)/restore/$', CustomerProjectRestoreView.as_view(), name='customer-project-restore'), + urls.url(r'^(?P\d+)/delete/$', CustomerProjectDeleteView.as_view(), name='customer-project-delete'), + urls.url(r'^(?P\d+)/answer/$', ContractorProjectAnswerView.as_view(), name='contractor-project-answer'), urls.url(r'^candidate/add/(?P(\d+))/(?P(\d+))/$', add_candidate, name='add-candidate'), urls.url(r'^candidate/comparison/(?P\d+)$', ProjectComparisonView.as_view(), name='comparison'), - urls.url(r'^create/$', ProjectCreateView.as_view(), name='project-create'), # urls.url(r'^portfolio/create/$', PortfolioCreateView.as_view(), name='portfolio-create'), urls.url(r'chat/$', ChatView.as_view(), name='chat'), urls.url(r'offerorder/(?P(\d+))/(?P(\d+))/$', OfferOrderView.as_view(), name='offer-order'), diff --git a/projects/views.py b/projects/views.py index ce5c5b0..2c875d4 100644 --- a/projects/views.py +++ b/projects/views.py @@ -8,22 +8,95 @@ from django.views.generic.base import ContextMixin from pprint import pprint, pformat import pydash as _ +from .mixins import LastAccessMixin from .models import Project, Portfolio, Candidate, Answer, Realty, Order from archilance.mixins import BaseMixin from users.models import User from .forms import ( - AnswerForm, + ContractorProjectAnswerForm, + CustomerProjectCreateForm, PortfolioForm, ProjectDeleteForm, ProjectEditForm, - ProjectForm, ProjectRestoreForm, ProjectTrashForm, RealtyForm, ) -from .mixins import LastAccessMixin + +# class CustomerProjectCreateView(PermissionRequiredMixin, View): +# permission_required = ('projects.add_project',) +# form_realty = RealtyForm +# form_project = CustomerProjectCreateForm +# raise_exception = True +# permission_denied_message = 'Вы не можете выполнить это действие' +# template_name = 'customer_project_create.html' +# +# def get(self, request, *args, **kwargs): +# form_project = self.form_project() +# form_realty = self.form_realty(prefix='form_2') +# realty_list = Realty.objects.all() +# return render(request, self.template_name, {'form_project': form_project, +# 'form_realty': form_realty, +# 'realty_list': realty_list}) +# +# def post(self, request, *args, **kwargs): +# form_project = self.form_project(request.POST) +# form_realty = self.form_realty(request.POST, prefix='form_2') +# if form_project.is_valid() and form_realty.is_valid(): +# return self.form_valid(request, form_project, form_realty) +# return render(request, self.template_name, {'form_project': form_project, 'form_realty': form_realty}) +# +# +# def form_valid(self, request, form_project, form_realty): +# realty = form_realty.save(commit=False) +# realty.user = request.user +# realty.save() +# project = form_project.save(commit=False) +# project.customer = request.user +# project.realty = realty +# project.save() +# +# return HttpResponseRedirect('/projects/') + + +class CustomerProjectCreateView(BaseMixin, View): + form_class = CustomerProjectCreateForm + template_name = 'customer_project_create.html' + + def get(self, request, *args, **kwargs): + if request.user.is_authenticated() and request.user.is_customer(): + form = self.form_class(request=request) + + context = self.get_context_data(**_.merge({}, request.GET, kwargs)) + context.update({'form': form}) + + return render(request, self.template_name, context) + else: + return HttpResponseForbidden('403 Forbidden') + + def post(self, request, *args, **kwargs): + if request.user.is_authenticated() and request.user.is_customer(): + form = self.form_class(_.merge({}, request.POST, kwargs), request=request) + + if form.is_valid(): + project = form.save(commit=False) + project.customer = request.user + project.save() + form.save_m2m() + + messages.info(request, 'Проект успешно создан') + redirect_to = reverse('projects:detail', kwargs={'pk': project.pk}) + return redirect(redirect_to) + else: + context = self.get_context_data(**kwargs) + context.update({'form': form}) + + messages.info(request, 'Произошла ошибка:
    {msg}
    '.format(msg=pformat(form.errors))) + return render(request, self.template_name, context) + else: + return HttpResponseForbidden('403 Forbidden') class ProjectsView(ListView): @@ -31,19 +104,66 @@ class ProjectsView(ListView): template_name = 'project_list.html' -class ProjectView(LastAccessMixin, View): - model = Project - form_class = AnswerForm - template_name = 'contractor_project_detail.html' - - def get_success_url(self): - return reverse('projects:detail', kwargs={'pk': self.object.pk}) +class ProjectView(BaseMixin, View): + template_name = 'project_detail.html' + customer_template_name = 'customer_project_detail.html' def get(self, request, *args, **kwargs): - if request.user.is_customer(): - self.template_name = 'customer_project_detail.html' - project = get_object_or_404(Project, pk=kwargs.get('pk')) - return render(request, self.template_name, {'project': project, 'form': self.form_class}) + if request.user.is_authenticated() and request.user.is_customer(): + project = get_object_or_404(request.user.projects, pk=kwargs.get('pk')) + + context = self.get_context_data(**_.merge({}, request.GET, kwargs)) + context.update({'project': project}) + + return render(request, self.customer_template_name, context) + else: + project = get_object_or_404(Project, pk=kwargs.get('pk')) + + context = self.get_context_data(**_.merge({}, request.GET, kwargs)) + context.update({'project': project}) + + return render(request, self.template_name, context) + + +class CustomerProjectEditView(BaseMixin, View): + form_class = ProjectEditForm + template_name = 'customer_project_edit_test.html' # 'customer_project_edit.html' + + def get(self, req, *args, **kwargs): + if req.user.is_authenticated(): + project = get_object_or_404(req.user.projects, pk=kwargs.get('pk')) + form = self.form_class(instance=project, req=req) + + context = self.get_context_data(**_.merge({}, req.GET, kwargs)) + context.update({'form': form}) + + return render(req, self.template_name, context) + else: + return HttpResponseForbidden('403 Forbidden') + + def post(self, req, *args, **kwargs): + if req.user.is_authenticated(): + project = get_object_or_404(req.user.projects, pk=kwargs.get('pk')) + form = self.form_class(_.merge({}, req.POST, kwargs), req=req, instance=project) + + if form.is_valid(): + form.save() + + messages.info(req, 'Проект успешно отредактирован') + redirect_to = req.POST.get('next') + return redirect(redirect_to) + else: + context = self.get_context_data(**kwargs) + context.update({'form': form}) + + messages.info(req, 'Произошла ошибка:
    {msg}
    '.format(msg=pformat(form.errors))) + return render(req, self.template_name, context) + else: + return HttpResponseForbidden('403 Forbidden') + + +class ContractorProjectAnswerView(BaseMixin, View): + form_class = ContractorProjectAnswerForm def post(self, request, *args, **kwargs): if not request.user.is_authenticated(): @@ -60,53 +180,11 @@ class ProjectView(LastAccessMixin, View): answer.project = project answer.save() order = Order.objects.create(project=project) - + return HttpResponseRedirect(reverse('projects:detail', kwargs={'pk': project.pk})) -class ProjectTestView(DetailView): - model = Project - template_name = 'test.html' - - -class ProjectCreateView(PermissionRequiredMixin, View): - permission_required = ('projects.add_project',) - form_realty = RealtyForm - form_project = ProjectForm - raise_exception = True - permission_denied_message = 'Вы не можете выполнить это действие' - template_name = 'customer_project_create.html' - - def get(self, request, *args, **kwargs): - form_project = self.form_project() - form_realty = self.form_realty(prefix='form_2') - realty_list = Realty.objects.all() - return render(request, self.template_name, {'form_project': form_project, - 'form_realty': form_realty, - 'realty_list': realty_list}) - - def post(self, request, *args, **kwargs): - form_project = self.form_project(request.POST) - form_realty = self.form_realty(request.POST, prefix='form_2') - if form_project.is_valid() and form_realty.is_valid(): - return self.form_valid(request, form_project, form_realty) - return render(request, self.template_name, {'form_project': form_project, 'form_realty': form_realty}) - - - def form_valid(self, request, form_project, form_realty): - realty = form_realty.save(commit=False) - realty.user = request.user - realty.save() - project = form_project.save(commit=False) - project.customer = request.user - project.realty = realty - project.save() - - return HttpResponseRedirect('/projects/') - - - -class ProjectTrashView(View): +class CustomerProjectTrashView(View): form_class = ProjectTrashForm def post(self, req, *args, **kwargs): @@ -128,7 +206,7 @@ class ProjectTrashView(View): return redirect(redirect_to) -class ProjectRestoreView(View): +class CustomerProjectRestoreView(View): form_class = ProjectRestoreForm def post(self, req, *args, **kwargs): @@ -150,7 +228,7 @@ class ProjectRestoreView(View): return redirect(redirect_to) -class ProjectDeleteView(View): +class CustomerProjectDeleteView(View): form_class = ProjectDeleteForm def post(self, req, *args, **kwargs): @@ -172,43 +250,6 @@ class ProjectDeleteView(View): return redirect(redirect_to) -class ProjectEditView(BaseMixin, View): - form_class = ProjectEditForm - template_name = 'project_edit_test.html' # 'project_edit.html' - - def get(self, req, *args, **kwargs): - if req.user.is_authenticated(): - project = get_object_or_404(req.user.projects, pk=kwargs.get('pk')) - form = self.form_class(instance=project, req=req) - - context = self.get_context_data(**kwargs) - context.update({'form': form}) - - return render(req, self.template_name, context) - else: - return HttpResponseForbidden('403 Forbidden') - - def post(self, req, *args, **kwargs): - if req.user.is_authenticated(): - project = get_object_or_404(req.user.projects, pk=kwargs.get('pk')) - form = self.form_class(_.merge({}, req.POST, kwargs), req=req, instance=project) - - if form.is_valid(): - form.save() - - messages.info(req, 'Проект успешно отредактирован') - redirect_to = req.POST.get('next') - return redirect(redirect_to) - else: - context = self.get_context_data(**kwargs) - context.update({'form': form}) - - messages.info(req, 'Произошла ошибка:
    {msg}
    '.format(msg=pformat(form.errors))) - return render(req, self.template_name, context) - else: - return HttpResponseForbidden('403 Forbidden') - - class ProjectComparisonView(DetailView): model = Project template_name = 'comparison.html' diff --git a/users/templates/customer_profile_open_projects.html b/users/templates/customer_profile_open_projects.html index ef72104..c1a0559 100644 --- a/users/templates/customer_profile_open_projects.html +++ b/users/templates/customer_profile_open_projects.html @@ -31,7 +31,9 @@
@@ -72,11 +74,11 @@
  • - Редактировать + Редактировать
  • - + {% csrf_token %} diff --git a/users/templates/customer_profile_trashed_projects.html b/users/templates/customer_profile_trashed_projects.html index 4c37995..4be67cb 100644 --- a/users/templates/customer_profile_trashed_projects.html +++ b/users/templates/customer_profile_trashed_projects.html @@ -29,7 +29,9 @@
-

Разместить заказ

+

+ Разместить заказ +

@@ -71,7 +73,7 @@