Skip to content

Commit 8887d2b

Browse files
trcochristianwgdmarkmonoaDramaQueen
authored
New major release 3.0.0 (#216)
* Fix waring from BSModalDeleteView / DeleteMessageMixin with Django 4 * fix when form has field named method * add new mixin for FormValidation, remove SuccessMessageMixin dependecy * Updated project to current Django LTS version Updated deprecated "is_safe_url" function to "url_has_allowed_host_and_scheme". Added automatically database population, if DB is empty. Updated requirements to current version. Updated settings. Removed outdated version support. Updated gitignore. * Minor refactoring * Updated Project Added type hints. Updated test cases. Removed last remaining snippets for outdated Django versions. * Removed unused constant * Updated required version * Minor Bugfix Removed __slots__ from dataclass, to match Python 3.8 support. * refactor save method in CreateUpdateAjaxMixin * remove compatibility.py * remove utils.py * remove types * add is_ajax method and remove imports * remove unneeded class inheritence * remove obsolete class name parameter * revert examples to version in master branch * remove static folder * remove types from tests * remove unneeded comments * update get and set for form action and method attributes * update bootstrap5.modal.forms.min.js * update assert string to pass the test * update DeleteMessageMixin comment * cleanup .gitignore --------- Co-authored-by: Christian Wiegand <christianwgd@users.noreply.github.com> Co-authored-by: Mark Monaghan <markmono@gmail.com> Co-authored-by: aDramaQueen <richard.saeuberlich@o2online.de>
1 parent ca1fa95 commit 8887d2b

File tree

22 files changed

+193
-245
lines changed

22 files changed

+193
-245
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ database/db.sqlite3
22
geckodriver.log
33
__pycache__
44
*.pyc
5-
.env/
5+
.env/

bootstrap_modal_forms/compatibility.py

Lines changed: 0 additions & 84 deletions
This file was deleted.

bootstrap_modal_forms/generic.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,22 @@
1-
import django
2-
from django.contrib.messages.views import SuccessMessageMixin
31
from django.views import generic
4-
from .mixins import PassRequestMixin, DeleteMessageMixin, LoginAjaxMixin
2+
from django.contrib.auth.views import LoginView
53

6-
DJANGO_VERSION = django.get_version().split('.')
7-
DJANGO_MAJOR_VERSION = DJANGO_VERSION[0]
8-
DJANGO_MINOR_VERSION = DJANGO_VERSION[1]
4+
from .mixins import PassRequestMixin, DeleteMessageMixin, LoginAjaxMixin, FormValidationMixin
95

10-
# Import custom LoginView for Django versions < 1.11
11-
if DJANGO_MAJOR_VERSION == '1' and '11' not in DJANGO_MINOR_VERSION:
12-
from .compatibility import LoginView
13-
else:
14-
from django.contrib.auth.views import LoginView
156

16-
17-
class BSModalLoginView(LoginAjaxMixin, SuccessMessageMixin, LoginView):
7+
class BSModalLoginView(LoginAjaxMixin, LoginView):
188
pass
199

2010

2111
class BSModalFormView(PassRequestMixin, generic.FormView):
2212
pass
2313

2414

25-
class BSModalCreateView(PassRequestMixin, SuccessMessageMixin, generic.CreateView):
15+
class BSModalCreateView(PassRequestMixin, FormValidationMixin, generic.CreateView):
2616
pass
2717

2818

29-
class BSModalUpdateView(PassRequestMixin, SuccessMessageMixin, generic.UpdateView):
19+
class BSModalUpdateView(PassRequestMixin, FormValidationMixin, generic.UpdateView):
3020
pass
3121

3222

bootstrap_modal_forms/mixins.py

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,96 @@
11
from django.contrib import messages
22
from django.contrib.auth import login as auth_login
3-
from django.http import HttpResponseRedirect
3+
from django.http import HttpResponseRedirect, HttpResponse
44

5-
from .utils import is_ajax
6-
7-
8-
class PassRequestMixin(object):
5+
class PassRequestMixin:
96
"""
10-
Mixin which puts the request into the form's kwargs.
7+
Form Mixin which puts the request into the form's kwargs.
118
129
Note: Using this mixin requires you to pop the `request` kwarg
1310
out of the dict in the super of your form's `__init__`.
1411
"""
1512

1613
def get_form_kwargs(self):
17-
kwargs = super(PassRequestMixin, self).get_form_kwargs()
18-
kwargs.update({'request': self.request})
14+
kwargs = super().get_form_kwargs()
15+
kwargs['request'] = self.request
1916
return kwargs
2017

2118

22-
class PopRequestMixin(object):
19+
class PopRequestMixin:
2320
"""
24-
Mixin which pops request out of the kwargs and attaches it to the form's
21+
Form Mixin which pops request out of the kwargs and attaches it to the form's
2522
instance.
2623
2724
Note: This mixin must precede forms.ModelForm/forms.Form. The form is not
2825
expecting these kwargs to be passed in, so they must be popped off before
2926
anything else is done.
3027
"""
3128

32-
def __init__(self, *args, **kwargs):
29+
def __init__(self, *args, **kwargs) -> None:
3330
self.request = kwargs.pop('request', None)
34-
super(PopRequestMixin, self).__init__(*args, **kwargs)
31+
super().__init__(*args, **kwargs)
3532

3633

37-
class CreateUpdateAjaxMixin(object):
34+
class CreateUpdateAjaxMixin:
3835
"""
39-
Mixin which passes or saves object based on request type.
36+
ModelForm Mixin which passes or saves object based on request type.
4037
"""
4138

4239
def save(self, commit=True):
43-
if not is_ajax(self.request.META) or self.request.POST.get('asyncUpdate') == 'True':
44-
instance = super(CreateUpdateAjaxMixin, self).save(commit=commit)
45-
else:
46-
instance = super(CreateUpdateAjaxMixin, self).save(commit=False)
47-
return instance
40+
isAjaxRequest = is_ajax(self.request.META)
41+
asyncUpdate = self.request.POST.get('asyncUpdate') == 'True'
42+
43+
if not isAjaxRequest or asyncUpdate:
44+
return super().save(commit=commit)
45+
if isAjaxRequest:
46+
return super().save(commit=False)
4847

4948

50-
class DeleteMessageMixin(object):
49+
class DeleteMessageMixin:
5150
"""
52-
Mixin which adds message to BSModalDeleteView and only calls the delete method if request
53-
is not ajax request.
51+
Generic View Mixin which adds message to BSModalDeleteView and only calls the post method if request
52+
is not ajax request. In case request is ajax post method calls delete method, which redirects to success url.
5453
"""
55-
56-
def delete(self, request, *args, **kwargs):
54+
55+
def post(self, request, *args, **kwargs):
5756
if not is_ajax(request.META):
5857
messages.success(request, self.success_message)
59-
return super(DeleteMessageMixin, self).delete(request, *args, **kwargs)
58+
return super().post(request, *args, **kwargs)
6059
else:
6160
self.object = self.get_object()
6261
return HttpResponseRedirect(self.get_success_url())
6362

64-
class LoginAjaxMixin(object):
63+
64+
class LoginAjaxMixin:
6565
"""
66-
Mixin which authenticates user if request is not ajax request.
66+
Generic View Mixin which authenticates user if request is not ajax request.
6767
"""
6868

6969
def form_valid(self, form):
7070
if not is_ajax(self.request.META):
7171
auth_login(self.request, form.get_user())
7272
messages.success(self.request, self.success_message)
73-
return HttpResponseRedirect(self.get_success_url())
73+
return HttpResponseRedirect(self.get_success_url())
74+
75+
76+
class FormValidationMixin:
77+
"""
78+
Generic View Mixin which saves object and redirects to success_url if request is not ajax request. Otherwise response 204 No content is returned.
79+
"""
80+
81+
def form_valid(self, form):
82+
isAjaxRequest = is_ajax(self.request.META)
83+
asyncUpdate = self.request.POST.get('asyncUpdate') == 'True'
84+
85+
if isAjaxRequest:
86+
if asyncUpdate:
87+
form.save()
88+
return HttpResponse(status=204)
89+
90+
form.save()
91+
messages.success(self.request, self.success_message)
92+
return HttpResponseRedirect(self.success_url)
93+
94+
95+
def is_ajax(meta):
96+
return 'HTTP_X_REQUESTED_WITH' in meta and meta['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'

bootstrap_modal_forms/static/js/bootstrap5.modal.forms.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const modalFormCallback = function (settings) {
2525

2626
let form = modal.querySelector(settings.modalForm);
2727
if (form) {
28-
form.action = settings.formURL;
28+
form.setAttribute("action", settings.formURL);
2929
addEventHandlers(modal, form, settings)
3030
}
3131
});
@@ -57,9 +57,9 @@ const isFormValid = function (settings, callback) {
5757

5858
let btnSubmit = modal.querySelector('button[type="submit"]');
5959
btnSubmit.disabled = true;
60-
fetch(form.action, {
60+
fetch(form.getAttribute("action"), {
6161
headers: headers,
62-
method: form.method,
62+
method: form.getAttribute("method"),
6363
body: new FormData(form),
6464
}).then(res => {
6565
return res.text();
@@ -73,7 +73,7 @@ const isFormValid = function (settings, callback) {
7373
return;
7474
}
7575

76-
form.action = settings.formURL;
76+
form.setAttribute("action", settings.formURL);
7777
addEventHandlers(modal, form, settings)
7878
} else {
7979
callback(settings);
@@ -97,8 +97,8 @@ const submitForm = function (settings) {
9797
// Add asyncUpdate and check for it in save method of CreateUpdateAjaxMixin
9898
formData.append("asyncUpdate", "True");
9999

100-
fetch(form.action, {
101-
method: form.method,
100+
fetch(form.getAttribute("action"), {
101+
method: form.getAttribute("method"),
102102
body: formData,
103103
}).then(res => {
104104
return res.text();
@@ -142,7 +142,7 @@ const submitForm = function (settings) {
142142
return;
143143
}
144144

145-
form.action = settings.formURL;
145+
form.setAttribute("action", settings.formURL);
146146
addEventHandlers(modal, form, settings)
147147
});
148148
}
@@ -156,7 +156,6 @@ const submitForm = function (settings) {
156156
};
157157

158158
const validateAsyncSettings = function (settings) {
159-
console.log(settings)
160159
var missingSettings = [];
161160

162161
if (!settings.successMessage) {

bootstrap_modal_forms/static/js/bootstrap5.modal.forms.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bootstrap_modal_forms/utils.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

examples/admin.py

Lines changed: 0 additions & 3 deletions
This file was deleted.

examples/apps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33

44
class ExamplesConfig(AppConfig):
5-
name = 'examples'
5+
name = 'examples'

examples/forms.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ class Meta:
3333
class CustomAuthenticationForm(AuthenticationForm):
3434
class Meta:
3535
model = User
36-
fields = ['username', 'password']
36+
fields = ['username', 'password']

0 commit comments

Comments
 (0)