GithubHelp home page GithubHelp logo

jrief / django-formset Goto Github PK

View Code? Open in Web Editor NEW
278.0 9.0 25.0 5.12 MB

The missing widgets and form manipulation library for Django

Home Page: https://django-formset.fly.dev/

License: MIT License

TypeScript 30.40% SCSS 3.25% Python 56.35% HTML 7.53% CSS 0.61% JavaScript 0.84% PEG.js 0.75% Dockerfile 0.21% Shell 0.05%
forms django form datepicker datetimepicker formsets select2 calendar daterangepicker datetimerangepicker

django-formset's Introduction

Jacob Rief profile views

django-formset's People

Contributors

dependabot[bot] avatar franga2000 avatar jrief avatar lolrenx avatar ozgur-as avatar tobi-de avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-formset's Issues

Uncaught DOMException when using stylesheets with external @import

When trying to include a bootstrap theme, the django-formset script broke:
Uncaught DOMException: CSSStyleSheet.cssRules getter: Not allowed to access cross-origin stylesheet [helpers.ts:1:7]

This is the theme I was trying to use: https://bootswatch.com/5/flatly/bootstrap.css
I'm certain it is the external @import for the fonts at the top of that file. If I comment it out, it works fine.

A small example: https://github.com/Actionb/formset-css-import

selectize losing its selected status when filter_by is defined

i'm using 2 modelchoicefields in my modelform definition, the second one is filtered by the first one's id like it's given in the example(17.2.2. Filtering Select Options).

when looking at an editview for the said model, the second field loses its preselected choice. the form is prefilled properly when i remove the filter_by definition.

i am thinking it's a js problem since when i look at the source of the page, the proper option's selected tag is rendered in html.

thanks in advance!

How to specify the css framework with FormCollection

Hi, first of all thank you for your work, this is a really wonderful django package.
I read the documentation, but I couldn't find anywhere how to specify the css framework to use with the form collection.
Here is the code I am working with:

#forms.py
class ActivityFormCollection(FormCollection):
    ...

class WorkflowForm(forms.Form):
  ...

class WorkflowFormCollection(FormCollection):
    workflow = WorkflowForm()
    activities = ActivityFormCollection()

#views.py
from formset.views import FormCollectionView

from .forms import WorkflowFormCollection

create_workflow = FormCollectionView.as_view(
    collection_class=WorkflowFormCollection,
    template_name="workflows/create.html",
    success_url="/success",
)

the html code

{% extends "base.html" %}
{% load static formsetify %}

{% block content %}
  <django-formset endpoint="{{ request.path }}">
    {% with dummy=csrf_token.0 %}{% endwith %}
    {{ form_collection }}
  </django-formset>
{% endblock content %}

It seems that the default style is the one applied

Django-formset - i am facing the issue - Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

i am facing the following error in my modelchoice control change event

Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

MY CODE

my model
class Places(models.Model):
placename = models.CharField(max_length=50,unique=True)
blockname = models.CharField(max_length=50)
pincode = models.CharField(max_length=6)
TALUKNAME = models.CharField(max_length=50)
rev_dist = models.ForeignKey(REVDISTDET, on_delete=models.CASCADE, verbose_name='REVENUE DISTRICT',default='',null=True, )
edn_dist = models.ForeignKey(EDNDISTDET, on_delete=models.CASCADE, verbose_name='REVENUE DISTRICT',default='',null=True, )

def __str__(self):
    return self.placename

class Meta:
    ordering = ('placename',)

class Officedet(models.Model):

PlaceArea=[('1','Rural'),('2','Urban'),('3', 'NOT APPLICABLE'), ]
YesNo=[('Y','YES'),('N','NO'),('NA', 'NOT APPLICABLE'),]
office_type_choice = [
    ('SCHOOL','SCHOOL'),
    ('ADMIN','ADMIN'),

]
office_code = models.CharField(max_length=15,unique=True)
office_name = models.CharField(max_length=150)
office_address = models.CharField(max_length=250, verbose_name='Address')
office_area = models.CharField(max_length=10,choices = PlaceArea,verbose_name='Area Rural/Urban')
phone_regex = RegexValidator(regex=r'^[789]\d{9}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
office_phone = models.CharField(max_length=10,validators=[phone_regex])
office_head_name = models.CharField(max_length=50,verbose_name='Head Name')
office_head_phone1 = models.CharField(max_length=10,validators=[phone_regex],verbose_name='Office Head Contact Number')
office_head_phone2 = models.CharField(max_length=10,validators=[phone_regex],verbose_name='Office Head Whatsapp Number')
office_mail = models.EmailField(max_length=50,unique=True)
office_place = models.ForeignKey('Places', on_delete=models.CASCADE)

my form
class OfficedetForm(forms.ModelForm):

office_logo = fields.FileField(
    label="Office Logo",
    widget=UploadedFileInput,
    required=True,
)

office_gender_type = forms.ModelChoiceField(
    queryset=OFFICE_GENDER_TYPE_CHOICE.objects.all(),
    widget=Selectize(
        
        placeholder="Choose Gender",
    ),
)

office_mgnt_type = forms.ModelChoiceField(
    queryset=OFFICE_MGNT_TYPE_CHOICE.objects.all(),
    widget=Selectize(
        
        placeholder="Choose Management",
    ),
)

office_class_level = forms.ModelChoiceField(
    queryset=OfficeClassLevel.objects.all(),
    widget=Selectize(
        
        placeholder="Choose Class Level",
    ),
)

office_place = forms.ModelChoiceField(
    queryset=Places.objects.all(),
    widget=Selectize(
        search_lookup='placename__icontains',
        placeholder="Choose Place",
        
    ),
)

office_type = forms.ChoiceField(
    choices=[ ('SCHOOL','SCHOOL'),
    ('ADMIN','ADMIN'),],
    widget=Selectize,
)


default_renderer = FormRenderer(
    form_css_classes='row',
    field_css_classes={
        '*': 'mb-2 col-12', 
        "office_code": 'mb-2 col-2', 
        "office_name": 'mb-2 col-4',
        "office_mail": 'mb-2 col-3',
        "office_place": 'mb-2 col-3',
         '*': 'mb-2 col-12', 
        "office_gender_type": 'mb-2 col-3', 
        "office_mgnt_type": 'mb-2 col-3',
        "office_class_level": 'mb-2 col-3',
        "office_type": 'mb-2 col-3',

         '*': 'mb-2 col-12', 
        "office_tanno": 'mb-2 col-4', 
        "office_udisecode": 'mb-2 col-4', 
        "office_logo": 'mb-2 col-4', 


        }
        )
class Meta:
    model = Officedet
    fields = ["office_code",

"office_name",
"office_mail",
"office_place",
"office_gender_type",
"office_mgnt_type",
"office_class_level",
"office_type",
'office_tanno',
'office_udisecode',
"office_logo",
]

My view
class OfficeDetailCreateView(AdminUserTypeAuthMixin,FileUploadMixin, FormViewMixin, LoginRequiredMixin, CreateView):
model = Officedet
template_name = 'home/crud/crud_template.html'
form_class = OfficedetForm
success_url = reverse_lazy('office_list_view') # or whatever makes sense
extra_context = {
'pagetitle':'Office Creation'
}
my template
{% extends "layouts/masterpage-formset.html" %}
{% block pagecontent %}
{% load render_form from formsetify %}

{% render_form form %}

Submit Reset Back to list
{% endblock pagecontent %}

Radio buttons in a form not rendered properly when adding new siblings

I'm having issues rendering radio buttons if I create a new sibling.

Example of radio button without selection yet:
image

After I added a new sibling

Rendered radio button after creating new sibling
image

here's a snippet of the form and form collection

# BaseModelForm inherits forms.ModelForm
class MyForm(BaseModelForm): 
...
    is_retired = forms.ChoiceField(required=False,
                                   widget=forms.RadioSelect, label='Is retired?',
                                   choices=RadioButtonChoices.choices)
...

# BaseFormCollection inherits formset.collection.FormCollection
class MyFormCollection(BaseFormCollection):
...
    my_form = MyForm()
    min_siblings = 1
...

Is it possible to pass parameter to a form __init__ in a collection?

I have a form class contained in a FormCollection.

My form has an __init__ method which expects additional parameters, such as the request object. How can I pass the request object to the form, provided that the form is created by the FormCollection code behind the scenes? In vanilla Django, I would use the get_form_kwargs method of my FormView class view.

Thank you!

RichTextarea not displaying correctly in a Bootstrap modal

I have the following form.

forms.py

class PersonForm(forms.Form):
    name = fields.CharField()
    text = fields.CharField(widget=RichTextarea())

which is rendered using:

urls.py

    path(
        "test_form/",
        FormView.as_view(
            form_class=PersonForm,
            template_name="test_form/test_form.html",
            success_url="/test_form/",
        ),
    ),

test_form.html (modal code copied from: Bootstrap docs)

{% load static %}
{% load render_form from formsetify %}
<!DOCTYPE html>
<html dir="ltr" lang="{{ LANGUAGE_CODE|default:'en' }}">

<head>
	<meta charset="utf-8"/>
	<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0"/>
	<title>Django-Formset Demo</title>
	<link href="{% static 'vendor/bootstrap/dist/css/bootstrap.min.css' %}" rel="stylesheet" type="text/css" media="screen">
	<script type="module" src="{% static 'formset/js/django-formset.js' %}"></script>
</head>

<body>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <django-formset endpoint="{{ request.path }}" csrf-token="{{ csrf_token }}">
          {% render_form form "bootstrap" field_classes="mb-4" form_classes="rounded-xl" %}
          <button type="button" df-click="submit -> proceed">Submit</button>
        </django-formset>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
  Launch demo modal
</button>
</body>
<script src="{% static 'vendor/bootstrap/dist/js/bootstrap.min.js' %}"></script>
</html>

Which results in:
Screenshot 2024-01-10 at 13 00 06

Hence the Charfield renders correctly but not the RichTextarea...

p.s. Outside the model everything renders correctly.

Getting a 404 from <script type="module" src="{% static 'formset/js/django-formset.min.js' %}"></script>

Hi,
Thank you for an awesome package. This feels like it should be the default way to deal with forms.

I was trying to test it on a project after reading docs, and got a 404 when I tried to load

<script type="module" src="{% static 'formset/js/django-formset.min.js' %}"></script>

I checked the source and couldn't find the .min.js file, there was however a django-formset.js file that seems like it is minified.
I changed it to:

<script type="module" src="{% static 'formset/js/django-formset.js' %}"></script> and the error is gone.

Incompatible with django-recaptcha

Many sites need to prevent misuse by bots, and this is often accomplished with Google reCAPTCHA. The package django-recaptcha allows this to be integrated into a Django form.

Unfortunately, at present django-formset appears to be incompatible with django-recaptcha.

I've created a test case to demonstrate this; please see eab80b7.

At the moment I'm not sure precisely what the issue is that prevents reCAPTCHA from working. I get the following error from the django test server:
WARNING: Unprocessable Entity: /bootstrap/article-captcha

Additionally, Google Chrome shows the response from the server as {"captcha": ["This field is required."]}.

Uncaught error when using MultiWidget

When using a MultiValueField with a MultiWidget widget, assertUniqueName in DjangoFormset.ts throws an error:
Uncaught Error: Duplicate name 'phone_number_0' on multiple input fields on 'phone_number_1'

Example: Actionb@6555d75

Tom Select already initialized on this element

Hello, I've found an error with the Selectize/Tom-select widget.
When I move child form with Selectize widget in a sortable FormCollection I get errors:
Tom Select already initialized on this element
image

I've already tried it here https://django-formset.fly.dev/bootstrap/sortablecontact where I added Selectize widget to label (

label = fields.ChoiceField(
)

    label = fields.ChoiceField(
        label="Label",
        choices=[
            ('home', "Home"),
            ('work', "Work"),
            ('mobile', "Mobile"),
            ('other', "Other"),
        widget=Selectize,
        ],
    )

and it also didn't work without errror.

Selectize with 'dynamic' choices: front-end search hides back-end results

For model choice fields with a selectize widget, the results of the back-end query are filtered again in the front-end (by sifter, I assume). This hides results the back-end query has found.

Take the State model from the test app:

class State(models.Model):
    code = models.CharField(
        verbose_name="Code",
        max_length=2,
    )

    name = models.CharField(
        verbose_name="Name",
        max_length=20,
        db_index=True,
    )

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

Assume you have a widget like this:
Selectize(search_lookup=['name__icontains', 'code__icontains'])
And a State like this:
State(name='foo', code='bar')

In the form, you want to find the state by its code, bar. The back-end query will find that state no problem, and the view will add it to the available options "options": [{"id": 1, "label": "Foo"}]}. But then the front-end will do another search on these options for the search term bar - and will not find any matches.

DatePicker Uncaught Error

version: 1.1.1

DateTimePicker-QJNPLAAA.js:1  Uncaught Error: Unknown aria-label on [object HTMLDivElement]
    at c.getViewMode (DateTimePicker-QJNPLAAA.js:1:8877)
    at c.registerElement (DateTimePicker-QJNPLAAA.js:1:14462)
    at MutationObserver.observe.childList (DateTimePicker-QJNPLAAA.js:1:8511)

What happens:

  • popup of widget overlays entire page instead of date widget

WARNING: "GET /static/formset/js/django-formset.js HTTP/1.1" 404 1843

Version: django-formset==1.0.1

similar case to #27, I followed instructions in https://django-formset.fly.dev/development/#developing-in-django-formset

Trying to reproduce issue reported in #28 since I am experiencing the same problem in my app. Wanted to investigate and follow the code for IncompleteSelectResponseMixin

Can't seem to find django-formset.js in static files or in anywhere in the repository, so I can't investigate.

I also tried to reverse it back to django-formset.min.js but it also can't find the file nor can I find the file in the repository

Hoping for some resolution. Thanks!

Error with float fields

If there is a float field in the form, the following error happens:

  [...]
  File "[...]/lib/python3.9/site-packages/formset/boundfield.py", line 125, in css_classes
    return super().css_classes(extra_classes)
  File "[...]/lib/python3.9/site-packages/django/forms/boundfield.py", line 218, in css_classes
    if self.errors and hasattr(self.form, "error_css_class"):
  File "[...]/lib/python3.9/site-packages/formset/boundfield.py", line 75, in errors
    errors.client_messages = self._get_client_messages()
  File "[...]/lib/python3.9/site-packages/formset/boundfield.py", line 194, in _get_client_messages
    step_value = float(self.field.widget.attrs['step'])
  ValueError: could not convert string to float: 'any'

how to save data in FormCollectionView

please help me. I can't save data in FormCollectionView

class QuestionTrainingCreateView(LoginRequiredMixin, PermissionRequiredMixin, FormCollectionView): template_name = 'question_training/create.html' collection_class = ContactCollection success_url = '/path/to/success',

Use GET method instead of POST during submit button

Is it possible to invoked GET method instead of POST when submitting a django-formset form.

I'm creating a filter using django-filterset and rendering the said form in my template using render_form tag.

But everytime I click the submit button to filter my queryset, I can see that POST method is getting invoked.

template.html

<div class="form-group">
    <div class="card">
        <h3>Filter By:</h3>
        <br>
        <!--TODO: Fix style of filter forms-->
        <django-formset endpoint="{{ request.path }}" csrf-token="{{ csrf_token }}">
        {% render_form filterset.form "bootstrap" field_classes="pb-3 mb-2" %}

        <div class="d-flex align-items-center justify-content-md-end">
            <button class="primaryAction btn btn-primary" click="disable -> spinner -> submit -> proceed !~ scrollToError">Submit</button>
        </div>

        </django-formset>
    </div>
</div>

bug in uploadedfileinput widget

hi there,

in my own project, i am using a collection to be able to add multiple images in a single form. i have come across a bug, so i wanted to reproduce it in the testapp with a simple gallery example. you can access the branch from: https://github.com/ozgur-as/django-formset/tree/reproduce-file-input-widget-bug

the example works as it should if you are just uploading for the first time/deleting/updating and doing a form submit after each action, but if you do the following actions without submitting the form the bug occurs:

  • "add image" <- first image
  • "choose file, browse, do the temporary upload" <- first image
  • "add image" <- second image
  • "choose file, browse, do the temporary upload" <- second image
  • "delete the first image"
  • "click add image"

browser console throws the following javascript error:

django-formset.js:25 Uncaught Error: More than one form has id="id_images.2.image"
    at dr.assignFieldsToForms (django-formset.js:25:27803)
    at HTMLButtonElement.appendFormCollectionSibling (django-formset.js:25:24025)

the widget's progress bar and choose file button stays unresponsive and submitted form would not save properly because of the mixed id's i suppose.

i hope it's a clear description of the steps :)

thanks in advance!

Missing csrf token FormCollection

I'm getting a (CSRF token missing.) when I submit a form collection.
here is my setup

{% extends "base.html" %}
{% load static formsetify %}

{% block content %}
  <django-formset endpoint="{{ request.path }}">
    {% with dummy=csrf_token.0 %}{% endwith %}
    {{ form_collection }}
    <div class="">
      <button type="button"
              click="disable -> submit -> proceed !~ scrollToError"
              class="btn btn-primary">Submit<span
        class="ms-2 dj-button-decorator"><i class="dj-icon">{% include "formset/icons/send.svg" %}</i></span></button>
      <button type="button" click="reset" class="ms-2 btn btn-warning">Reset to initial<span
        class="ms-2 dj-button-decorator"><i class="dj-icon">{% include "formset/icons/backspace.svg" %}</i></button>
    </div>
  </django-formset>
{% endblock content %}
# forms.py
class WorkflowFormCollection(FormCollection):
    default_renderer = FormRenderer()
    workflow = WorkflowForm()
    activities = ActivityFormCollection(
        min_siblings=1, max_siblings=10, extra_siblings=1
    )

# views.py

from formset.views import FormCollectionView

from .forms import WorkflowFormCollection


class CreateWorkflowView(FormCollectionView):
    collection_class = WorkflowFormCollection
    template_name = "workflows/create.html"

    def form_collection_valid(self, form_collection: WorkflowFormCollection):
        print(form_collection)
        return JsonResponse({'success_url': self.get_success_url()})

When running locally your bootstap 11-contactlist demo does the same things, the form is submitted with a crsf token missing printout in the console.

Selectize accessibility issues

Just came across this library and it's great so far!

Trying the Selectize widget, I have noticed accessibility is off. One way to tell is that navigating the options using the keyboard doesn't work. Pressing the up/down key doesn't move the focused option.

I checked the docs of Tom-Select and can't really tell what is going wrong in django-formset. Maybe someone else has a clue?

DualSortableSelector not loading correctly

Versions
Django==4.2.1
django-formset==0.13.4

Description
I have a django app that has a form that contains a DualSortableSelector widget according to the docs https://django-formset.readthedocs.io/en/latest/dual-selector.html#

# Form
class OpenDataStoreForm(forms.ModelForm):
    class Meta:
        model = OpenDataStore
        fields = ('slug', 'name', 'categories', 'comment')

        widgets = {
            'categories': DualSortableSelector(search_lookup='name__icontains'),
        }
# models
class OpenDataStore(OpenDataBaseModel):
    name = models.CharField(max_length=128, unique=True)
    categories = SortableManyToManyField(OpenDataCategory, through='tandoor.OpenDataStoreCategory')


class OpenDataStoreCategory(models.Model):
    store = models.ForeignKey(OpenDataStore, on_delete=models.PROTECT)
    category = models.ForeignKey(OpenDataCategory, on_delete=models.PROTECT)
    weight = models.BigIntegerField(default=0, db_index=True, )

    class Meta:
        ordering = ['weight']


class OpenDataProperty(OpenDataBaseModel):
    name = models.CharField(max_length=128, unique=True)
    unit = models.CharField(max_length=16, unique=True)

# Form View

class OpenDataStoreUpdate(UpdateView, FormView):
    template_name = "open_data/edit_template.html"
    model = OpenDataStore
    form_class = OpenDataStoreForm
<div class="row">
        <div class="col">
            <django-formset endpoint="{{ request.path }}" csrf-token="{{ csrf_token }}">

                {% render_form form "bootstrap" field_classes="mb-2" %}

                <button class="btn btn-success" type="button" click="submit -> proceed"><i
                        class="fal fa-save"></i> {% trans 'Save' %}</button>
            </django-formset>

        </div>
    </div>

The form can be opened, the categories can be assigned to the store and can be ordered and saved. The weight attribute is set in the db correctly according to the order that is choosen in the user interface.

The problem is when i re-open the form the DualSortableSelector widget loads the categories based on their ID order and not ordered by weight so that when I save the form again the order is lost.

Steps to reproduce

  1. order categories c1-c5 (ID corresponds to name)
    image
  2. database is correct
    image
  3. reload the form -> ordering is default (ID asc) again
    image

Note
What is interesting is that other than on the screenshots in the docs when i click on an entry in the right table its not highlighted as a selected entry (but i can still sort it)

Thanks for this awesome library btw. its something I have always wanted and seems incredibly powerful and thank you in advance for any help.

pre select - state - example

when i try to implement in my model object i got this error

[25/Mar/2023 10:01:59] "GET /office_add_view/undefined?offset=0&filter-Class_code=11&field=undefined HTTP/1.1" 200 6984

Please help what wrong in this code

class ClassDet(models.Model):

Class_code = models.CharField(max_length = 4,unique=True)
Class_name = models.CharField(max_length = 4)
def __str__(self):
    return self.Class_name

class GroupCode(models.Model):

Group_code = models.CharField(max_length = 4)
Group_name = models.CharField(max_length = 300)
Class_code = models.ForeignKey('ClassDet', on_delete=models.CASCADE)
class Meta:
    unique_together = ('Group_code','Class_code',)
    
def save(self, *args, **kwargs):
    for field_name in ['Group_code','Group_name',]:
        val = getattr(self, field_name, False)
        if val:
            setattr(self, field_name, val.upper())
    super(GroupCode, self).save(*args, **kwargs)
def __str__(self):
    return self.Group_code + '-' + self.Group_name

class GroupSubject(models.Model):

Class_code = models.ForeignKey(ClassDet, on_delete=models.SET_NULL, null=True)
Group_code =  models.ForeignKey(GroupCode, on_delete=models.SET_NULL, null=True)


class Meta:
    unique_together = ('Class_code', 'Group_code','subject_code')

form

Group_code = forms.ModelChoiceField(
queryset=GroupCode.objects.all(),
widget=Selectize(

        filter_by={"Class_code" : "Class_code_id"},
    ),
    required=False,
)

Collections for related models do not know their parent instance during validation

Carrying on from #55

For (unique) validation, collections for related models may need to know the parent instance of the relation.

Inline formsets are instantiated with the parent instance of the relation, and that instance is passed on to the model forms as data for the InlineForeignKeyField. This way, the parent id is available for validation - most notably unique_together validation.

This does not happen for collections for related models.
You can work around this when editing existing relations of an existing parent: since model_to_dict includes the parent in the initial data of the relation's model form, you just need to include the formfield for the parent in the model form and it validates properly.
However, this doesn't work when you are adding a 'new parent', or a new relation to an existing parent. You need to validate the model form of the parent first, and then you can grab the form's instance and pass it on to the related collections. For example like it is done in django admin.

Currently when adding a new related object that would violate unique constraints, the validation for unique_together is skipped when the form of the new object is first validated, because the parent field is missing data. Later, when trying to save the duplicate object, the parent instance is available, and a second validation of the form in construct_instance fails as expected due to the unique constraint. The duplicate object is never saved, but the user doesn't know about this, because they are never presented an error.

How to ignore this field

image

{
  "full_name": "First Last",
  "gender": "f",
  "pregnant": true
}

image

{
  "full_name": "First Last",
  "gender": "m",
  "pregnant": true
}

When i switch to "Male", "pregnant:true" still in submitted data.

I expect the pregnant field to be ignored.

How to ignore this field?

Developer instructions out of date

The developer set up instructions seem to be out of date (here).

Currently, it lists the following commands:

git clone https://github.com/jrief/django-formset.git
cd django-formset
python -m venv .venv
source .venv/bin/activate
pip install -r testapp/requirements.txt
pip install --no-deps -e .
npm install --also=dev
npm run tag-attributes
npm run tailwindcss
npm run build
testapp/manage.py migrate
testapp/manage.py runserver

Instead, based on the test.yml file, I had to use the following commands to get the test site to run:

git clone https://github.com/jrief/django-formset.git
cd django-formset
python3 -m venv .venv
source .venv/bin/activate
pip install "Django==4.1.*"
pip install -r testapp/requirements.txt
pip install --no-deps -e .
npm install --include=dev
npm run tag-attributes
npm run tailwindcss
npm run esbuild
npm run compilescss
mkdir workdir
testapp/manage.py migrate
testapp/manage.py runserver

This also doesn't seem to install bootstrap in the test app, so I get the following warnings from the devel server:

WARNING: Not Found: /static/node_modules/bootstrap/dist/css/bootstrap.min.css
WARNING: "GET /static/node_modules/bootstrap/dist/css/bootstrap.min.css HTTP/1.1" 404 179

Installation error

After following the installation instructions in the docs. I recieved a:

ModuleNotFoundError: No module named 'phonenumbers'

which was caused by line two in:

formset/templatetags/phonenumber.py

I resolved this by:
pip install django-phonenumbers

This is a dependency this should be mentioned in the docs.

Problem when using selectize together with a google translate snippet

Hello, I'm using the following snippet on my site to enable google translate:

      <script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
      <script type="text/javascript">
        function googleTranslateElementInit() {
          new google.translate.TranslateElement({
            pageLanguage: 'el',
            includedLanguages: 'en',
            layout: google.translate.TranslateElement.InlineLayout.SIMPLE
          }, 'google_translate_element');
        }
      </script>

Now, when I try to use the selectize widget I get the following warning and a similar error:

chunk-65OJRBX6.js:1 Could not read stylesheet, try adding crossorigin="anonymous" CSSStyleSheet {ownerRule: null, type: 'text/css', href: 'https://www.gstatic.com/_/translate_http/_/ss/k=tr…=AN8SPfq5gedF4FIOWZgYyMCNZA5tU966ig/m=el_main_css', ownerNode: link, parentStyleSheet: null, …}cssRules: (...)disabled: falsehref: "https://www.gstatic.com/_/translate_http/_/ss/k=translate_http.tr.qhDXWpKopYk.L.W.O/am=wA/d=0/rs=AN8SPfq5gedF4FIOWZgYyMCNZA5tU966ig/m=el_main_css"media: MediaList {length: 0, mediaText: ''}ownerNode: linkownerRule: nullparentStyleSheet: nullrules: (...)title: nulltype: "text/css"[[Prototype]]: CSSStyleSheet DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
    at Object.i [as convertPseudoClasses] (http://127.0.0.1:8000/static_ehcg/formset/js/chunk-65OJRBX6.js:1:358)
    at http://127.0.0.1:8000/static_ehcg/formset/js/django-formset.js:25:33876
chunk-65OJRBX6.js:1 Uncaught DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
    at Object.d [as stylesAreInstalled] (http://127.0.0.1:8000/static_ehcg/formset/js/chunk-65OJRBX6.js:1:761)
    at new ke (http://127.0.0.1:8000/static_ehcg/formset/js/chunk-NH2NEJWE.js:1:50837)
    at tt.connectedCallback (http://127.0.0.1:8000/static_ehcg/formset/js/chunk-NH2NEJWE.js:1:56521)
    at n (http://127.0.0.1:8000/static_ehcg/formset/js/django-formset.js:25:34004)
    at http://127.0.0.1:8000/static_ehcg/formset/js/django-formset.js:25:34237

This results to broken styles of the selectize element.

Please notice that if I remove the google translate snippet everything seems to be working fine.

Thank you

FormCollection with readonly fields

Hello,
In a form where I want to display fields as readonly, I overrided the init method of the ModelForm and set something like this:

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["serial"].disabled = True
        self.fields["serial"].required = False

It works as expected in a Form, but not in a FormCollection. In the latter, the value is taken into account and submitted to the DB.

Form collections: extra siblings are validated even if untouched

When you add extra siblings (be it via the extra_siblings parameter or by clicking the add button) to a form collection, the data of those extra collections is sent to the server to be validated - regardless of whether they have been touched/filled out by the user. If the extra collections are found to be invalid (which is likely; they're untouched), the user is forced to remove them by hand by clicking the remove button before they can successfully submit the form.

extra_siblings_validation
(ContactCollection with testapp.forms.contact.PhoneNumberForm.phone_number field set to be required)

This is problematic when the collection is declared with extra_siblings: if the user decides not to make use of the offered extra collections, they must remove them although they never added them in the first place. And when using the add button, the user is forced to clean up after themselves.

My understanding was that adding extra siblings is an optional thing; kind of an invitation to add data - not a requirement. So extra collections that have not been interacted with should just be ignored and be discarded upon submit (if the min_siblings requirement is satisfied, of course).
What's your take on this?

Feedback richtext-editor

The appearance and the function of the editor are so far already very good.

The following changes seem to be easily possible:

  • Headline to h4
  • Regroup elements and arrange them differently (e.g. all text alignments together etc.)
  • Remove underline

Elements that are still missing from the font formatting:

  • List
  • small font, large font

Insert a horizonal line generates the following HTML: <hr contenteditable="false">.
However, in Django we have the following structure for thehorizonal line:
<div class="rule-uibk-orange1 cms-plugin cms-plugin-3066987"><hr></div>

Indentation:
<p data-text-indent="1">
Shouldn't this also be solved with CSS classes?

Is it possible that I can also make changes?

Buttons are completely unresponsive. A simple model utilizing the example from Chapter 9 of the docs produces a dead add button.

I can't get even the simplest model/form button to work using the example in Chapter 9 of the documentation. The following example doesn't throw any errors in the browser console.

#models.py:

from django.db import models

class Customer(models.Model):
    first_name = models.CharField('First Name', max_length=55, blank=True)

#forms.py:

from django import forms
from .models import *

class CustomerForm(forms.ModelForm):
    class Meta:
        model = Customer
        fields = '__all__'

#views.py:

from django.views.generic import UpdateView, ListView
from django.utils.encoding import force_str
from django.http.response import JsonResponse
from django.urls import reverse_lazy

from formset.views import EditCollectionView, FormCollectionView, FormView, FileUploadMixin, FormViewMixin

from .forms import *
from .models import *


class CustomerEditView(FormViewMixin, UpdateView):
    model = Customer
    template_name = 'testing/customer-edit.html'
    form_class = CustomerForm
    success_url = reverse_lazy('customer-list')
    extra_context = None

    def get_object(self, queryset=None):
        if self.extra_context['add'] is False:
            return super().get_object(queryset)

    def form_valid(self, form):
        if extra_data := self.get_extra_data():
            if extra_data.get('delete') is True:
                self.object.delete()
                success_url = self.get_success_url()
                response_data = {'success_url': force_str(success_url)} if success_url else {}
                return JsonResponse(response_data)
        return super().form_valid(form)


class CustomerListView(ListView):
    model = Customer

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

#urls.py:

from django.urls import path, re_path

from .views import *

urlpatterns = [
    path('', CustomerListView.as_view(), name='customer-list'),  # list view not handled here
    path('add/', CustomerEditView.as_view(extra_context={'add': True}),
         name='customer-add',
         ),
    path('<int:pk>/', CustomerEditView.as_view(extra_context={'add': False}),
         name='customer-edit',
         ),
]

#customer-edit.html:

{% load i18n %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{% load render_form from formsetify %}

<django-formset endpoint="{{ request.path }}" csrf-token="{{ csrf_token }}">
  {% render_form form %}
  {% if add %}
    <button type="button" click="submit({add: true}) -> proceed">{% trans "Add" %}</button>
  {% else %}
    <button type="button" click="submit({update: true}) -> proceed">{% trans "Update" %}</button>
    <button type="button" click="submit({delete: true}) -> proceed">{% trans "Delete" %}</button>
  {% endif %}

</django-formset>
</body>
</html>

I came across this issue while I was testing/debugging for my project. I thought it maybe had something to do with not loading the typescript implementation of 'click' based on the error I got but this simple example presents the same problem, although without this error:

Uncaught DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
at Object.i [as convertPseudoClasses] (http://127.0.0.1:8001/static/formset/js/chunk-KFPGMBXM.js:1:354)
at http://127.0.0.1:8001/static/formset/js/django-formset.js:25:29909

Model form validation in collections: instance attribute not set

Collections create a copy of the underlying form for validation via HolderMixin.replicate. But replicate does not assign a model instance to model forms, leading to issues with validation.
When creating a new object, this isn't an issue. But when editing an existing object, the form's instance attribute must be set to that object for uniqueness validation to work properly.

To clarify, this only affects validation, more specifically uniqueness validation, because the unique checks take the instance's state and primary key into account: model._perform_unique_checks. Note that including the primary key field in the form is not enough: the form's model instance was instantiated as new object and it will remain so - instance._state.adding remains True until the object was saved.

To set the correct instance, I suggest trying to fetch the existing object from the database when the form is being replicated. I can whip up a PR if you want.

Use emit() to forward response data

I've created a search form where you the user can enter search criteria and when they hit submit, the search results would, ideally, appear below the form. I'm using FormCollectionView to create the form as the user can add multiple criteria forms before submitting. I'm using the form_collection_valid method to get the cleaned_data so I can perform the search on the database. But at this point I'm not sure how to return the results to the browser. This method can only return a success_url. Is there a way to return the results via Ajax, so the page doesn't reload? I can save the values to the database and my success_url have parameters to reference the saved data, but I would prefer to do this all in the same view, if possible, and not have to save the data if the user doesn't need it for later.

Originally posted by @anthonycalvano in #62

Cannot get demo to run, error during `tag-attributes`

I wanted to try out the demo and during tag-attributes I get the following:

> [email protected] tag-attributes
> peggy -o client/django-formset/tag-attributes.ts --extra-options-file assets/pegjsconf.json --plugin ./node_modules/ts-pegjs/src/tspegjs.js assets/tag-attributes.pegjs

Cannot find module 'pegjs/lib/compiler/asts'
Require stack:
- /tmp/django-formset/node_modules/ts-pegjs/src/passes/generate-bytecode-ts.js
- /tmp/django-formset/node_modules/ts-pegjs/src/tspegjs.js
- /tmp/django-formset/node_modules/peggy/bin/peggy

My npm version (if relevant) is 8.0.0, aside from that I simply followed the instructions. npm install looked relatively normal:

npm WARN old lockfile 
npm WARN old lockfile The package-lock.json file was created with an old version of npm,
npm WARN old lockfile so supplemental metadata must be fetched from the registry.
npm WARN old lockfile 
npm WARN old lockfile This is a one-time fix-up, please be patient...
npm WARN old lockfile 
⸨##################⸩ ⠴ reify:foundation-sites: http fetch GET 200 https://registry.npmjs.org/foundation-sites/-/foundation-sites-6.6.3.tgz 9194ms (cache miss

added 199 packages, and audited 200 packages in 2m

22 packages are looking for funding
  run `npm fund` for details

1 moderate severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.
npm notice 
npm notice New minor version of npm available! 8.0.0 -> 8.1.3
npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.1.3
npm notice Run npm install -g [email protected] to update!
npm notice 

What can I try, any other information I can provide you with (sorry I have literally close to zero ideas on how to fix JS issues :D)?

Update of FormCollection with UniqueConstraint not possible

Hello,

when I submit a EditCollectionView, where I can update the FormCollection, which has not been changed at all, the Form complains that it is invalid because of a unique constraint which is set.

class UpdateTermCollectionView(EditCollectionView):
    model = Term
    collection_class = TermFormCollection
    template_name = 'glossary/term_update.html'
    success_url = reverse_lazy('glossary:index')
class TermFormCollection(FormCollection):
    default_renderer = FormRenderer()
    term = TermForm()
    synonyms = SynonymCollection()
class Term(TimeStampedModel, models.Model):
    title_de = models.CharField(max_length=250, help_text="Term in German")
    title_en = models.CharField(max_length=250, help_text="Term in British English")
    source = models.CharField(max_length=20, choices=SOURCE_CHOICES)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=["title_de", "source"], name='unique_term_source'),
        ]

When I remove the unique constraint, it works as expected.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.