Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version upgrade #34

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ repos:
rev: 7.1.1
hooks:
- id: flake8
args: [--extend-ignore=E203, --extend-ignore=E501, --extend-ignore=W605, --extend-ignore=W504, --extend-ignore=E265, --extend-ignore=W503]
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Changelog
=========

0.5.0
-----
* Upgrades functionality for Django 4.2+
* Forked and taken over by Peter Natale

0.4.0
-----
* Fix formset rendering in Django 1.9. `#17`_
Expand Down
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Copyright (c) 2024, Peter Natale
Copyright (c) 2014, Gregor Müllegger

All rights reserved.
Expand Down
40 changes: 33 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ view is usually quite troublesome. You need to validate both the form and the
formset manually and you cannot use django's generic FormView_. So here comes
**django-superform** into play.

.. _formsets: https://docs.djangoproject.com/en/1.10/topics/forms/formsets/
.. _FormView: https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-editing/#formview
.. _formsets: https://docs.djangoproject.com/en/5.1/topics/forms/formsets/
.. _FormView: https://docs.djangoproject.com/en/5.1/ref/class-based-views/generic-editing/#formview

Here we have an example for the usecase. Let's have a look at the
``forms.py``:
Expand All @@ -37,7 +37,7 @@ Here we have an example for the usecase. Let's have a look at the
fields = ('account', 'email',)


EmailFormSet = modelformset_factory(EmailForm)
EmailFormSet = forms.models.modelformset_factory(EmailForm)


class SignupForm(SuperModelForm):
Expand All @@ -50,6 +50,32 @@ Here we have an example for the usecase. Let's have a look at the
fields = ('username',)


Alternatively, if you did not wish to use a formset_factory, model or inline, for InlineFormSetField,
you may pass it explicitly stated parent_model and model

.. code-block:: python

from django import forms
from django_superform import SuperModelForm, InlineFormSetField
from myapp.models import Account, Email


class EmailForm(forms.ModelForm):
class Meta:
model = Email
fields = ('account', 'email')


class SignupForm(SuperModelForm):
username = foms.charField()
# The model `Email` has a ForeignKey called `user` to `Account`.
emails=InlineFormSetField(parent_model=Account, model=Email)

class Meta:
model = Account
fields = ('username',)


So we assign the ``EmailFormSet`` as a field directly to the ``SignupForm``.
That's where it belongs! Ok and how do I handle this composite form in the
view? Have a look:
Expand Down Expand Up @@ -97,8 +123,8 @@ And it just works.
Requirements
------------

- Python 2.7 or Python 3.3+ or PyPy
- Django 1.4+
- Python 3.8+ or PyPy
- Django 4.2+

.. _Installation:

Expand All @@ -107,7 +133,7 @@ Installation

Install the desired version with pip_::

pip install django-superform
pip install django-superform4

.. _pip: https://pip.pypa.io/en/stable/

Expand All @@ -124,7 +150,7 @@ Then add ``django-superform`` to ``INSTALLED_APPS`` in your settings file:
Development
-----------

- Clone django-superform::
- Clone django-superform4::

git clone git@github.com:jazzband/django-superform.git

Expand Down
2 changes: 1 addition & 1 deletion django_superform/boundfield.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.forms.forms import BoundField
from django.forms import BoundField


class CompositeBoundField(BoundField):
Expand Down
32 changes: 24 additions & 8 deletions django_superform/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,10 @@ class RegistrationForm(SuperForm):
prefix_name = "form"
widget = FormWidget

def __init__(self, form_class, kwargs=None, **field_kwargs):
def __init__(self, form_class, kwargs=None, initial=None, **field_kwargs):
super(FormField, self).__init__(**field_kwargs)

self.initial = initial
self.form_class = form_class
if kwargs is None:
kwargs = {}
Expand All @@ -180,11 +181,18 @@ def get_form(self, form, name):
Get an instance of the form.
"""
kwargs = self.get_kwargs(form, name)
kwargs.update(
{
"use_required_attribute": (
False if kwargs.get("empty_permitted", False) is True else True
)
}
)
form_class = self.get_form_class(form, name)
composite_form = form_class(
data=form.data if form.is_bound else None,
files=form.files if form.is_bound else None,
**kwargs
**kwargs,
)
return composite_form

Expand Down Expand Up @@ -289,9 +297,15 @@ def save(self, form, name, composite_form, commit):

class ForeignKeyFormField(ModelFormField):
def __init__(
self, form_class, kwargs=None, field_name=None, blank=None, **field_kwargs
self,
form_class,
initial=None,
kwargs=None,
field_name=None,
blank=None,
**field_kwargs,
):
super(ForeignKeyFormField, self).__init__(form_class, kwargs, **field_kwargs)
super().__init__(form_class, kwargs, **field_kwargs)
self.field_name = field_name
self.blank = blank

Expand Down Expand Up @@ -358,9 +372,10 @@ class FormSetField(CompositeField):
prefix_name = "formset"
widget = FormSetWidget

def __init__(self, formset_class, kwargs=None, **field_kwargs):
def __init__(self, formset_class, initial=None, kwargs=None, **field_kwargs):
super(FormSetField, self).__init__(**field_kwargs)

self.initial = initial
self.formset_class = formset_class
if kwargs is None:
kwargs = {}
Expand All @@ -383,7 +398,7 @@ def get_formset(self, form, name):
formset = formset_class(
form.data if form.is_bound else None,
form.files if form.is_bound else None,
**kwargs
**kwargs,
)
return formset

Expand Down Expand Up @@ -447,11 +462,12 @@ class Meta:

def __init__(
self,
initial=None,
parent_model=None,
model=None,
formset_class=None,
kwargs=None,
**factory_kwargs
**factory_kwargs,
):
"""
You need to either provide the ``formset_class`` or the ``model``
Expand Down Expand Up @@ -506,7 +522,7 @@ def get_formset_class(self, form, name):
formset_class = inlineformset_factory(
self.get_parent_model(form, name),
self.get_model(form, name),
**self.formset_factory_kwargs
**self.formset_factory_kwargs,
)
return formset_class

Expand Down
11 changes: 5 additions & 6 deletions django_superform/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ def post_form(request):
from django import forms
from django.forms.forms import DeclarativeFieldsMetaclass, ErrorDict, ErrorList
from django.forms.models import ModelFormMetaclass
from django.utils import six
import copy

from .fields import CompositeField
Expand Down Expand Up @@ -155,10 +154,10 @@ class SuperFormMixin(object):
from django_superform import SuperFormMetaclass
import six

class MySuperForm(six.with_metaclass(
SuperFormMetaclass,
class MySuperForm(
SuperFormMixin,
MyCustomForm)):
MyCustomForm,
metaclass=SuperFormMetaclass):
pass

The goal of a superform is to behave just like a normal django form but is
Expand Down Expand Up @@ -373,7 +372,7 @@ def save_formsets(self, commit=True):


class SuperModelForm(
six.with_metaclass(SuperModelFormMetaclass, SuperModelFormMixin, forms.ModelForm)
SuperModelFormMixin, forms.ModelForm, metaclass=SuperModelFormMetaclass
):
"""
The ``SuperModelForm`` works like a Django ``ModelForm`` but has the
Expand All @@ -383,7 +382,7 @@ class SuperModelForm(
"""


class SuperForm(six.with_metaclass(SuperFormMetaclass, SuperFormMixin, forms.Form)):
class SuperForm(SuperFormMixin, forms.Form, metaclass=SuperFormMetaclass):
"""
The base class for all super forms. The goal of a superform is to behave
just like a normal django form but is able to take composite fields, like
Expand Down
19 changes: 5 additions & 14 deletions django_superform/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,22 @@ def get_context_data(self):
return {}

def get_context(self, name, value, attrs=None):
context = {
"name": name,
"hidden": self.is_hidden,
"required": self.is_required,
# In our case ``value`` is the form or formset instance.
"value": value,
}
context = super().get_context(name, value, attrs)
if self.value_context_name:
context[self.value_context_name] = value

if self.is_hidden:
context["hidden"] = True
context["widget"][self.value_context_name] = value

context.update(self.get_context_data())
context["attrs"] = self.build_attrs(attrs)

return context

def render(self, name, value, attrs=None, **kwargs):
def render(self, name, value, attrs=None, renderer=None, **kwargs):
template_name = kwargs.pop("template_name", None)
if template_name is None:
template_name = self.template_name
context = self.get_context(name, value, attrs=attrs or {}, **kwargs)
return loader.render_to_string(
template_name, dictionary=context, context_instance=self.context_instance
template_name,
context=context["widget"],
)


Expand Down
6 changes: 3 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,11 @@ def find_version(*file_paths):

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# 'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
Expand Down
16 changes: 15 additions & 1 deletion docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,18 @@
Quickstart
==========

TODO.
Installation
------------

* Install django-superform4::

pip install django-superform4

* Add ``'django_superform'`` to your ``INSTALLED_APPS`` settings::

INSTALLED_APPS = [
# other apps
"django_superform",
]

* Use like you would any other Form or Field. Subclass ``SuperModelForm`` to make ModelForms that can have InlineFormSetFields as fields
48 changes: 48 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[project]
name = "django-superform4"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you explicitly want to change the project name?

I am asking since this is only about adding support for recent Python and Django versions and not about an architectural change in the project.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My recommendation would be to stick with the same project name.

version = "0.5.0"
authors = [
{ name="Gregor Müllegger", email="gregor@mullegger.de" },
]
maintainers = [
{ name="Peter Natale", email="panatale1@gmail.com" },
]
description = "So much easier handling of formsets for Django 4.2+. Drop-in replacement for django-superform"
readme = "README.rst"
requires-python = ">=3.8"
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Framework :: Django",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
"Framework :: Django :: 5.1",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Intended Audience :: Developers",
"Natural Language :: English",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: User Interfaces",
"Development Status :: 3 - Alpha",
]
dependencies = [
"django>=4.2",
]
license = { file = "LICENSE" }
keywords = ["formsets", "form fields", "inline formsets"]

[project.urls]
Homepage = "https://github.com/panatale1/django-superform"
Documentation = "https://django-superform4.readthedocs.io"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["django_superform"]
4 changes: 2 additions & 2 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[pytest]
addopts = --cov=django_superform --cov-report=term-missing
python_paths = .
addopts = --cov=django_superform --cov-report=term-missing --import-mode=importlib
DJANGO_SETTINGS_MODULE=tests.settings
python_files = test_*.py
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Django>=1.8,<1.9
Sphinx==1.3.1
Django>=4.2
Sphinx==8.0.2
pre-commit
-r tests/requirements.txt
File renamed without changes.
4 changes: 2 additions & 2 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ class Post(models.Model):
"""

title = models.CharField(max_length=50)
series = models.ForeignKey("Series", null=True, blank=True)
series = models.ForeignKey(Series, null=True, blank=True, on_delete=models.CASCADE)


class Image(models.Model):
post = models.ForeignKey("Post", related_name="images")
post = models.ForeignKey(Post, related_name="images", on_delete=models.CASCADE)

name = models.CharField(max_length=50)
position = models.PositiveIntegerField(default=0)
Expand Down
Loading
Loading