CreateUpdateViewMixin.form_valid()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 7
rs 9.4285
cc 1
1
import operator
2
import six
3
from django.db.models import Q
4
from django.http import HttpResponseRedirect
5
from django.contrib.auth.views import redirect_to_login
6
from django.contrib.auth import REDIRECT_FIELD_NAME
7
from django.conf import settings
8
from django.contrib import messages
9
10
from crudbuilder.helpers import plural
11
from crudbuilder.signals import crudbuilder_signals
12
13
if six.PY3:
14
    from functools import reduce
15
16
17
class LoginRequiredMixin(object):
18
    """
19
    View mixin which verifies that login required for the crud builder
20
    """
21
    login_url = settings.LOGIN_URL
22
    redirect_field_name = REDIRECT_FIELD_NAME  # Set by django.contrib.auth
23
24
    def handle_login_required(self, request):
25
        return redirect_to_login(
26
            request.get_full_path(),
27
            self.login_url,
28
            self.redirect_field_name)
29
30
    def dispatch(self, request, *args, **kwargs):
31
        global_login_required = getattr(
32
            settings, 'LOGIN_REQUIRED_FOR_CRUD', False)
33
34
        if global_login_required or self.login_required:
35
            if not request.user.is_authenticated:
36
                return self.handle_login_required(request)
37
38
        return super(LoginRequiredMixin, self).dispatch(
39
            request, *args, **kwargs)
40
41
42
class PermissionRequiredMixin(object):
43
    """
44
    View mixin which verifies that the logged in user has the specified
45
    permission.
46
    """
47
    def check_permissions(self, request):
48
        perms = self.permissions
49
        result = request.user.has_perm(perms) if perms else True
50
        return result
51
52
    def dispatch(self, request, *args, **kwargs):
53
        has_permission = self.check_permissions(request)
54
        global_permission_required = getattr(
55
            settings, 'PERMISSION_REQUIRED_FOR_CRUD', False)
56
57
        if global_permission_required or self.permission_required:
58
            if not has_permission:
59
                return redirect_to_login(
60
                    request.get_full_path(),
61
                    settings.LOGIN_URL,
62
                    REDIRECT_FIELD_NAME)
63
64
        return super(PermissionRequiredMixin, self).dispatch(
65
            request, *args, **kwargs)
66
67
68
class CrudBuilderMixin(LoginRequiredMixin, PermissionRequiredMixin):
69
    """
70
    - Mixin to provide additional context data for the templates
71
    - app_label : return app_label for CRUD model
72
    - actual_model_name : returns the actual model name (person -> person)
73
    - pluralized_model_name : return the pluralized_model_name
74
    (person -> people)
75
    """
76
    def get_context_data(self, **kwargs):
77
        context = super(CrudBuilderMixin, self).get_context_data(**kwargs)
78
        model = context['view'].model
79
        context['app_label'] = model._meta.app_label
80
        try:
81
            context['exclude'] = self.detailview_excludes
82
        except:
83
            context['exclude'] = None
84
        context['actual_model_name'] = model.__name__.lower()
85
        context['pluralized_model_name'] = plural(model.__name__.lower())
86
        context['verbose_model_name'] = model._meta.verbose_name
87
        context['custom_postfix_url'] = self.custom_postfix_url
88
        context['verbose_model_name_plural'] = model._meta.verbose_name_plural
89
        context['project_name'] = getattr(
90
            settings, 'PROJECT_NAME', 'CRUDBUILDER')
91
        return context
92
93
    @property
94
    def get_actual_signal(self):
95
        view = 'update' if self.object else 'create'
96
        if self.inlineformset:
97
            return crudbuilder_signals['inlineformset'][view]
98
        else:
99
            return crudbuilder_signals['instance'][view]
100
101
102
class BaseDetailViewMixin(CrudBuilderMixin):
103
    def get_context_data(self, **kwargs):
104
        context = super(BaseDetailViewMixin, self).get_context_data(**kwargs)
105
        context['inlineformset'] = self.inlineformset
106
        return context
107
108
109
class CreateUpdateViewMixin(CrudBuilderMixin):
110
    """Common form_valid() method for both Create and Update views"""
111
    def get_form_kwargs(self):
112
        kwargs = super(CreateUpdateViewMixin, self).get_form_kwargs()
113
        if self.custom_form:
114
            kwargs.update({'request': self.request})
115
        return kwargs
116
117
    def form_valid(self, form):
118
        signal = self.get_actual_signal
119
        instance = form.save(commit=False)
120
        signal.send(sender=self.model, request=self.request, instance=instance)
121
        instance.save()
122
        form.save_m2m()
123
        return super(CreateUpdateViewMixin, self).form_valid(form)
124
125
126
class BaseListViewMixin(CrudBuilderMixin):
127
    """
128
    - Search implementation for tables2 in ListView.
129
    - search_fields will be defined in actual model
130
    - Override get_queryset method of ListView
131
    """
132
    def get_queryset(self):
133
        if self.custom_queryset:
134
            objects = self.custom_queryset(self.request, **self.kwargs)
135
        else:
136
            objects = self.model.objects.all()
137
        search = self.request.GET.get('search')
138
        if search:
139
            q_list = [
140
                Q(
141
                    ('{}__icontains'.format(field), search))
142
                for field in self.crud.search_fields
143
            ]
144
            objects = objects.filter(reduce(operator.or_, q_list))
145
        return objects.order_by('-pk')
146
147
    def get_context_data(self, **kwargs):
148
        context = super(BaseListViewMixin, self).get_context_data(**kwargs)
149
        if self.custom_context:
150
            custom_context = self.custom_context(self.request, context, **kwargs)
151
            context.update(custom_context)
152
        return context
153
154
155
class InlineFormsetViewMixin(CrudBuilderMixin):
156
    def get_context_data(self, **kwargs):
157
        context = super(
158
            InlineFormsetViewMixin, self).get_context_data(**kwargs)
159
        if self.request.POST:
160
            context['inlineformset'] = self.inlineformset(
161
                self.request.POST,
162
                instance=self.object
163
            )
164
        else:
165
            context['inlineformset'] = self.inlineformset(
166
                instance=self.object
167
            )
168
        return context
169
170
    def form_valid(self, form):
171
        context = self.get_context_data()
172
        inlineformset = context['inlineformset']
173
174
        if inlineformset.is_valid():
175
            parent = form.save(commit=False)
176
            inlineformset.instance = parent
177
            children = inlineformset.save(commit=False)
178
179
            # execute post signals
180
            signal = self.get_actual_signal
181
            signal.send(
182
                sender=self.model,
183
                request=self.request,
184
                parent=parent,
185
                children=children)
186
187
            parent.save()
188
            inlineformset.save()
189
            inlineformset.save_m2m()
190
191
            return HttpResponseRedirect(self.success_url)
192
        else:
193
            messages.error(
194
                self.request, inlineformset.non_form_errors())
195
            return self.render_to_response(
196
                self.get_context_data(form=form, inlineformset=inlineformset)
197
            )
198