Skip to content

Commit

Permalink
Merge pull request #315 from barseghyanartur/fix/308-checkbox-select-…
Browse files Browse the repository at this point in the history
…multiple-rendered-incorrectly-from-form-creation-page

Fix/308 checkbox select multiple rendered incorrectly from form creation page
  • Loading branch information
barseghyanartur authored Nov 12, 2023
2 parents d5eda65 + 61ffa86 commit 696b016
Show file tree
Hide file tree
Showing 24 changed files with 158 additions and 33 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pip-compile:
docker-compose -f docker-compose.yml exec -w /backend/examples/requirements/ backend pip-compile django_3_2.in
docker-compose -f docker-compose.yml exec -w /backend/examples/requirements/ backend pip-compile django_4_0.in
docker-compose -f docker-compose.yml exec -w /backend/examples/requirements/ backend pip-compile django_4_1.in
docker-compose -f docker-compose.yml exec -w /backend/examples/requirements/ backend pip-compile django_4_2.in
docker-compose -f docker-compose.yml exec -w /backend/examples/requirements/ backend pip-compile djangocms_3_4_3.in
docker-compose -f docker-compose.yml exec -w /backend/examples/requirements/ backend pip-compile djangorestframework.in
docker-compose -f docker-compose.yml exec -w /backend/examples/requirements/ backend pip-compile docs.in
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3'

services:
postgresql:
image: postgres
image: postgres:14-bullseye
restart: always
# network_mode: "host"
volumes:
Expand Down
7 changes: 3 additions & 4 deletions docker/backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM docker.io/python:3.10-slim
FROM docker.io/python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED 1

Expand All @@ -12,16 +12,15 @@ RUN apt-get update && \
nano \
chromium \
graphviz \
libpq-dev \
python3.9
libpq-dev

RUN pip install pip --upgrade
RUN pip install virtualenv

RUN mkdir /backend
WORKDIR /backend
ADD examples/requirements/ /backend/requirements/
RUN pip install -r /backend/requirements/django_4_1.in
RUN pip install -r /backend/requirements/django_4_2.in
#RUN python -c "import geckodriver_autoinstaller; print(geckodriver_autoinstaller.install())"
RUN python -c "from chromedriver_py import binary_path; print(binary_path)"
COPY . /backend/
Expand Down
2 changes: 1 addition & 1 deletion examples/requirements/common.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pickleshare>=0.5
Pillow>=4.2.1
pluggy>=0.7.1
ptyprocess>=0.5
psycopg2-binary>=2.8.2,<2.9
psycopg2-binary
Pygments>=2.0.2
pytz>=2019.1
#requests==2.8.1
Expand Down
2 changes: 1 addition & 1 deletion examples/requirements/django_4_1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ pluggy==1.0.0
# tox
pre-commit==2.20.0
# via -r style_checkers.in
psycopg2-binary==2.8.6
psycopg2-binary==2.9.9
# via -r common.in
ptyprocess==0.7.0
# via
Expand Down
15 changes: 15 additions & 0 deletions examples/requirements/django_4_2.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-r common.in
-r test.in
-r style_checkers.in
-r feincms_1_20.in

Django>=4.2,<5.0
django-admin-tools>=0.8.0
django-autoslug>=1.9.6
django-ckeditor>=5.8.0
django-debug-toolbar>=2.1
django-formtools>=2.2
django-registration>=3.1.1
django-simple-captcha>=0.5.12
djangorestframework>=3.10
easy-thumbnails>=2.7.0
Empty file.
12 changes: 12 additions & 0 deletions examples/simple/kitchen_sink/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django import forms


class KitchenSinkForm(forms.Form):
choices = forms.MultipleChoiceField(
choices=[
("a", "A"),
("b", "B"),
("c", "C"),
],
widget=forms.CheckboxSelectMultiple,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ message }}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
</body>
</html>
6 changes: 6 additions & 0 deletions examples/simple/kitchen_sink/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.urls import path
from .views import KitchenSinkFormView

urlpatterns = [
path("", KitchenSinkFormView.as_view(), name="kitchen_sink"),
]
12 changes: 12 additions & 0 deletions examples/simple/kitchen_sink/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.views.generic.edit import FormView
from django.urls import reverse, reverse_lazy

from .forms import KitchenSinkForm


class KitchenSinkFormView(FormView):
template_name = "kitchen_sink/kitchen_sink.html"
form_class = KitchenSinkForm

def get_success_url(self):
return f"{reverse('kitchen_sink')}?success"
1 change: 1 addition & 0 deletions examples/simple/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ def gettext(s):
# ***********************************************************************
# Other project specific apps
"foo", # Test app
"kitchen_sink", # Test app
]

STATIC_ROOT = PROJECT_DIR(os.path.join("..", "..", "static"))
Expand Down
26 changes: 23 additions & 3 deletions examples/simple/settings/docker.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
from chromedriver_py import binary_path
from selenium import webdriver

try:
from .local_settings_docker import DEBUG
except Exception as err:
DEBUG = True

try:
from .local_settings_docker import DEBUG_TOOLBAR
except Exception as err:
DEBUG_TOOLBAR = True

from .bootstrap3_theme import *


Expand All @@ -15,8 +25,8 @@ def gettext(s):


PROJECT_DIR = project_dir
DEBUG = True
DEBUG_TOOLBAR = False


DEBUG_TEMPLATE = True
# TEMPLATE_DEBUG = True
DEV = True
Expand Down Expand Up @@ -57,7 +67,11 @@ def gettext(s):
"page": "page.migrations",
}

INTERNAL_IPS = ("127.0.0.1",)
if DEBUG:
import socket # only if you haven't already imported this
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
INTERNAL_IPS = [ip[: ip.rfind(".")] + ".1" for ip in ips] + ["127.0.0.1", "10.0.2.2"]

ALLOWED_HOSTS = ["*"]

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
Expand Down Expand Up @@ -92,3 +106,9 @@ def gettext(s):
CHROME_DRIVER_EXECUTABLE_PATH = binary_path # '/usr/bin/chromedriver'
FIREFOX_BIN_PATH = "/usr/lib/firefox/firefox"
PHANTOM_JS_EXECUTABLE_PATH = ""

# Do not put any settings below this line
try:
from .local_settings_docker import *
except Exception as err:
pass
2 changes: 2 additions & 0 deletions examples/simple/settings/local_settings_docker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DEBUG = True
DEBUG_TOOLBAR = True
1 change: 1 addition & 0 deletions examples/simple/urls/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .class_based import *
# from .function_based import *
1 change: 1 addition & 0 deletions examples/simple/urls/class_based.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
url(r"^foo/", include("foo.urls")),
# bar URLs:
# url(r'^bar/', include('bar.urls')),
url(r"^kitchen-sink/", include("kitchen_sink.urls")),
url(r"^$", TemplateView.as_view(template_name=fobi_home_template)),
# django-fobi public forms contrib app:
# url(r'^', include('fobi.contrib.apps.public_forms.urls')),
Expand Down
7 changes: 5 additions & 2 deletions src/fobi/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3149,16 +3149,19 @@ def get_ignorable_form_fields(form_element_entries):
# *****************************************************************************


def get_cleaned_data(form, keys_to_remove=[], values_to_remove=[]):
def get_cleaned_data(form, keys_to_remove=None, values_to_remove=None):
"""Get cleaned data.
Gets cleaned data, having the trash (fields without values) filtered
out.
:param form:
:param iterable keys_to_remove:
:param iterable values_to_remove:
:return dict:
"""
if not keys_to_remove:
keys_to_remove = []
if not values_to_remove:
values_to_remove = get_ignorable_form_values()

Expand All @@ -3177,7 +3180,7 @@ def get_cleaned_data(form, keys_to_remove=[], values_to_remove=[]):
return ordered_cleaned_data


def get_field_name_to_label_map(form, keys_to_remove=[], values_to_remove=[]):
def get_field_name_to_label_map(form, keys_to_remove=None, values_to_remove=None):
"""Get field name to label map.
:param form:
Expand Down
6 changes: 4 additions & 2 deletions src/fobi/contrib/apps/drf_integration/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def get_processed_serializer_data(serializer, form_element_entries):


def get_field_name_to_label_map(
serializer, keys_to_remove=[], values_to_remove=[]
serializer, keys_to_remove=None, values_to_remove=None
):
"""Get field name to label map.
Expand All @@ -290,7 +290,7 @@ def get_field_name_to_label_map(
return field_name_to_label_map


def get_cleaned_data(serializer, keys_to_remove=[], values_to_remove=[]):
def get_cleaned_data(serializer, keys_to_remove=None, values_to_remove=None):
"""Get cleaned data.
Gets cleaned data, having the trash (fields without values) filtered
Expand All @@ -301,6 +301,8 @@ def get_cleaned_data(serializer, keys_to_remove=[], values_to_remove=[]):
:param iterable values_to_remove:
:return dict:
"""
if not keys_to_remove:
keys_to_remove = []
if not values_to_remove:
values_to_remove = get_ignorable_form_values()

Expand Down
10 changes: 8 additions & 2 deletions src/fobi/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,18 @@ def map_field_name_to_label(form):
)


def clean_dict(source, keys=[], values=[]):
def clean_dict(source, keys=None, values=None):
"""Removes given keys and values from dictionary.
:param dict source:
:param iterable keys:
:param iterable values:
:return dict:
"""
if not keys:
keys = []
if not values:
values = []
dict_data = {}
for key, value in source.items():
if (key not in keys) and (value not in values):
Expand Down Expand Up @@ -338,13 +342,15 @@ def extract_file_path(name):
# *****************************************************************************


def get_registered_models(ignore=[]):
def get_registered_models(ignore=None):
"""Gets registered models as list.
:param iterable ignore: Ignore the following content types (should
be in ``app_label.model`` format (example ``auth.User``).
:return list:
"""
if not ignore:
ignore = []
get_models = django.apps.apps.get_models

registered_models = [
Expand Down
12 changes: 7 additions & 5 deletions src/fobi/templatetags/fobi_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,12 +411,14 @@ class FormFieldType(object):
is_radio = False
is_textarea = False

def __init__(self, properties=[]):
def __init__(self, properties=None):
"""Constructor.
By default all of them are false. Provide only property
names that should be set to True.
"""
if not properties:
properties = []
for prop in properties:
setattr(self, prop, True)

Expand All @@ -434,13 +436,13 @@ def render(self, context):
field = self.field.resolve(context, True)
properties = []

if isinstance(field.field.widget, forms.CheckboxInput):
properties.append("is_checkbox")

if isinstance(field.field.widget, forms.CheckboxSelectMultiple):
properties.append("is_checkbox_multiple")

if isinstance(field.field.widget, forms.RadioSelect):
elif isinstance(field.field.widget, forms.CheckboxInput):
properties.append("is_checkbox")

elif isinstance(field.field.widget, forms.RadioSelect):
properties.append("is_radio")

res = FormFieldType(properties)
Expand Down
17 changes: 12 additions & 5 deletions src/fobi/tests/test_core.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import logging

from django.test import RequestFactory, TestCase
from django.urls import reverse
Expand All @@ -23,6 +24,8 @@
__license__ = "GPL 2.0/LGPL 2.1"
__all__ = ("FobiCoreTest",)

LOGGER = logging.getLogger(__name__)


class FobiCoreTest(TestCase):
"""Tests of django-fobi core functionality."""
Expand Down Expand Up @@ -86,14 +89,18 @@ def _test_form_action_url(self, form_entry, action_url):
)
form = FormEntryForm(request.POST, request=request, instance=form_entry)

LOGGER.exception(f"action_url: {action_url}")

saved = False
try:

if form.is_valid():
form.save()
saved = True
except Exception:
pass
else:
LOGGER.exception(form.errors)
except Exception as err:
LOGGER.exception(err)

return saved

Expand Down Expand Up @@ -136,19 +143,19 @@ def test_05_action_url(self):

# External URL, OK test
saved = self._test_form_action_url(
form_entry, "http://delusionalinsanity.com/portfolio/"
form_entry, "https://github.com/barseghyanartur/django-fobi/"
)
self.assertTrue(saved)

# External URL, fail test
saved = self._test_form_action_url(
form_entry, "http://delusionalinsanity.com2/portfolio/"
form_entry, "https://github.com2/barseghyanartur/django-fobi/"
)
self.assertTrue(not saved)

# External URL, fail test
saved = self._test_form_action_url(
form_entry, "http://delusionalinsanity2.com/portfolio/"
form_entry, "https://github.com/barseghyanartur/django-fobi-i-do-not-exist/"
)
self.assertTrue(not saved)

Expand Down
Loading

0 comments on commit 696b016

Please sign in to comment.