andrewingram / django-extra-views Goto Github PK
View Code? Open in Web Editor NEWDjango's class-based generic views are awesome, let's have more of them.
License: MIT License
Django's class-based generic views are awesome, let's have more of them.
License: MIT License
When a CreateView fails to validate and is redisplayed, inline formsets with data (text, checkbox, etc) are correctly populated. However, an inline formset for file uploads doesn't repopulate. Is there any way to do this?
In django-extra-views/extra_views/multi.py, line 178, you mistakenly put return self.post(_args, *_kwargs) instead of return self.post(request, _args, *_kwargs).
Sometimes we want to pass additional stuff to the inline formset and form constructors based on the view's kwargs, so inlines need to be given access to these variables.
Please, create a complete and complex sample project using django-extra-views.
django-extra-views supports nested inlines, similar to the django-nested-inline[1] makes?
Could someone point me in the direction for how to implement prefetch_related with inline formset views? I have tried to manually override querysets, but these seem to get ignored. Am I missing something? I have a model with lots of inlines and loading the page takes very long depending on the size of the model. My other views that do much more intensive querying are almost instantaneous because of prefetch_related and select_related.
CreateWithInlinesView and UpdateWithInlinesView incorrectly fail to validate the inline formsets if the parent form doesn't validate.
Should copy functionality from django.contrib.admin.options.ModelAdmin.add_view and change_view.
Needs unit test.
It would be great if we could have more than one formset per view.
Hi Andrew,
Having spent the day reviewing your code and the tickets over on Django I can't seem to figure out how to define a:
DetailWithInlineView
I see UpdateWithInlinesView and the CreateWithInlinesView but that is for either creating the View or simultaneously updating it. Coule I ask you to show me how you would do this. FWIW I am OK with a DetailWithInlinesView (add 's').
FWIW I think you code is way more usable than rasca's enhanced-cbv. I think you should narrow this scope down to formsets and submit them into Django. This is very useful. I could help if needed.
class PhoneInline(GenericInlineFormSet):
model = Phone
max_num = 1
class ContactCreateView(BaseSingleClient, CreateWithInlinesView):
model = UpstreamContactModel
inlines = [PhoneInline, ]
template_name = 'clients/contact_form.html'
def get_initial(self):
initial = super(ContactCreateView, self).get_initial()
initial = initial.copy()
initial['client'] = self.kwargs['pk']
return initial
class Phone(models.Model):
TYPES_CHOICES = (
('HOME', 'Home'),
('WORK', 'Work'),
('MOBILE', 'Mobile'),
('HOME_FAX', 'Fax (home)'),
('WORK_FAX', 'Fax (work)'),
('PAGER', 'Pager'),
('OTHER', 'Other')
)
info = models.CharField('Phone Type', max_length=10, choices=TYPES_CHOICES)
number = models.CharField('Phone number', max_length=20)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class UpstreamContactModel(models.Model):
client = models.ForeignKey(UpstreamClientModel,
related_name='contacts')
contact_type = models.CharField(max_length=50, default='Main',
blank=True, null=True)
name = models.CharField(max_length=100, unique=True)
job_title = models.CharField(max_length=50, blank=True, null=True)
email = models.EmailField(blank=True, null=True)
skype_id = models.CharField(max_length=30, blank=True, null=True)
phones = generic.GenericRelation(Phone)
notes = models.TextField(blank=True, null=True)
def __unicode__(self):
return self.name
def get_absolute_url(self):
return reverse('client_list')
class Meta:
verbose_name = 'Contact'
(0.019) SELECT "clients_upstreamclientmodel"."id",
"clients_upstreamclientmodel"."client_name",
"clients_upstreamclientmodel"."url",
"clients_upstreamclientmodel"."language",
"clients_upstreamclientmodel"."is_active" FROM
"clients_upstreamclientmodel" WHERE "clients_upstreamclientmodel"."id"
= 1 ; args=(1,) DEBUG (0.000) SELECT (1) AS "a" FROM "clients_upstreamclientmodel" WHERE "clients_upstreamclientmodel"."id"
= 1 LIMIT 1; args=(1,) DEBUG (0.001) SELECT (1) AS "a" FROM "clients_upstreamcontactmodel" WHERE
"clients_upstreamcontactmodel"."name" = 'saasasa' LIMIT 1;
args=(u'saasasa',) DEBUG (0.001) INSERT INTO
"clients_upstreamcontactmodel" ("client_id", "contact_type", "name",
"job_title", "email", "skype_id", "notes") VALUES (1, 'Main',
'saasasa', 'sasasas', '', '', '') RETURNING
"clients_upstreamcontactmodel"."id"; args=(1, u'Main', u'saasasa',
u'sasasas', u'', u'', u'') ERROR Internal Server Error:
/clients/1/contacts/create/ Traceback (most recent call last): File
"/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/core/handlers/base.py",
line 111, in get_response
response = callback(request, _callback_args, *_callback_kwargs) File
"/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/views/generic/base.py",
line 48, in view
return self.dispatch(request, _args, *_kwargs) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/utils/decorators.py",
line 25, in _wrapper
return bound_func(_args, *_kwargs) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/contrib/auth/decorators.py",
line 20, in _wrapped_view
return view_func(request, _args, *_kwargs) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/utils/decorators.py",
line 21, in bound_func
return func(self, _args2, *_kwargs2) File "/Users/mirkocrocop/workspace/upstream_backend/my_auth/mixins.py",
line 22, in dispatch
return super(LoginRequiredMixin, self).dispatch(_args, *_kwargs) File
"/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/views/generic/base.py",
line 69, in dispatch
return handler(request, _args, *_kwargs) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/extra_views/advanced.py",
line 76, in post
return super(BaseCreateWithInlinesView, self).post(request, _args, *_kwargs) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/extra_views/advanced.py",
line 62, in post
return self.forms_valid(form, inlines) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/extra_views/advanced.py",
line 25, in forms_valid
self.object = form.save() File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/forms/models.py",
line 364, in save
fail_message, commit, construct=False) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/forms/models.py",
line 86, in save_instance
instance.save() File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/db/models/base.py",
line 463, in save
self.save_base(using=using, force_insert=force_insert, force_update=force_update) File
"/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/db/models/base.py",
line 551, in save_base
result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw) File
"/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/db/models/manager.py",
line 203, in _insert
return insert_query(self.model, objs, fields, **kwargs) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/db/models/query.py",
line 1593, in insert_query
return query.get_compiler(using=using).execute_sql(return_id) File
"/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/django/db/models/sql/compiler.py",
line 910, in execute_sql
cursor.execute(sql, params) File "/Users/mirkocrocop/.virtualenvs/upstream_backend/lib/python2.7/site-packages/debug_toolbar/utils/tracking/db.py",
line 152, in execute
'iso_level': conn.isolation_level, InternalError: current transaction is aborted, commands ignored until end of transaction
block
Hi,
Im doing a proyect with a master-detail form using CreateWithInlinesView for this functionallity,
but it doesn't save, simply the page is reloaded but with the same data in screen, and doesnt commit the transaction.
When the save button is clicked, nothings happen... any error, any message
Some help will be apreciate please!
_Models.py_
class Rekuest(AuditTable):
TYPEOWNER_CHOICES = (
('Empresarial', _(u'Enterprise')),
('Particular', _(u'Private'))
)
code = models.CharField(max_length=50, editable=False)
bpartner = models.ForeignKey(BPartner, verbose_name=_(u'Client'))
policy_type = models.ForeignKey(PolicyType)
type_owner = models.CharField(_(u'Type Owner'), max_length=15, choices = TYPEOWNER_CHOICES)
concept = models.CharField(_(u'Concept'), max_length=60, blank='True')
orderdate = models.DateField(_(u'Order Date'))
status = models.ForeignKey(Status)
requestedddate = models.DateTimeField(_(u'Requested Date'), null=True, blank=True)
finisheddate = models.DateTimeField(_(u'Finished Date'), null=True, blank=True)
promise_date = models.DateField(_(u'Promise Date'))
email = models.EmailField(_(u'Email'),null=True,blank=True)
is_active = models.BooleanField(_(u'Active'), default=True)
def get_next_code(self):
# Autocalculate next Request code
if not self.code and self.id:
num = 1
try:
lastcode = Rekuest.objects.exclude(pk=self.id).order_by('-id')[0].code
parts = lastcode.split('-')
num = int(parts[1]) + 1
except:
pass
return '%d-%03d' % (self.date.year, num)
else:
return self.code
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
self.code = self.get_next_code()
return AuditTable.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
def __unicode__(self):
return "[" + str(self.id) + "][" + str(self.orderdate) + "] " + self.bpartner.commercial_name
class Meta:
verbose_name = _('Request')
verbose_name_plural = _('Requests')
class RekuestDet(AuditTable):
CURRENCY_CHOICES = (
('MXN', _(u'MXN')),
('USD', _(u'USD'))
)
numrequest = models.ForeignKey(Rekuest, db_column='Rekuest_id')
bpartner_vendor = models.ForeignKey(BPartner, verbose_name=_(u'Insurance'))
currency = models.CharField(_(u'Currency'), max_length=15, choices = CURRENCY_CHOICES, default='MXN')
deductible = models.DecimalField(_(u'Deductible'), default=0,max_digits=15,decimal_places=2)
contact_name = models.CharField(_(u'Contact Name'),max_length=60)
phone1 = models.CharField(_(u'Phone'),max_length=60,blank='True')
paymentterm = models.ForeignKey(PaymentTerm, null='True')
description = models.TextField(_(u'Description'),max_length=200,null='True',blank='True')
num_cotization = models.TextField(_(u'Cotization No.'),max_length=20,null='True',blank='True')
priority = models.SmallIntegerField(_(u'Priority'),default=0,max_length=2)
price = models.DecimalField(_(u'Price'),default=0,max_digits=15,decimal_places=2)
tax = models.DecimalField(_(u'Price'),default=0,max_digits=15,decimal_places=2)
charges = models.DecimalField(_(u'Price'),default=0,max_digits=15,decimal_places=2)
others_charges = models.DecimalField(_(u'Price'),default=0,max_digits=15,decimal_places=2)
total = models.DecimalField(_(u'Price'),default=0,max_digits=15,decimal_places=2)
def get_absolute_url(self):
return None
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
#self.calculate()
return AuditTable.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
class Meta:
verbose_name = _('Request Detail')
verbose_name_plural = _('Request Detail')
_Forms.py_
class RekuestForm(forms.ModelForm):
orderdate = forms.DateField(widget=AdminDateWidget, initial=datetime.date.today, label=_(u'Date'))
promise_date = forms.DateField(label=_('Promised Date'), initial=datetime.date.today, required=False)
class Meta:
model = Rekuest
#exclude = ('company',)
class RekuestDetForm(forms.ModelForm):
price = forms.DecimalField(localize=True, decimal_places=2)
quantity = forms.IntegerField(localize=True)
class Meta:
model = RekuestDet
class RekuestDetInline(InlineFormSet):
model = RekuestDet
extra = 1 #extra = Numero de renglones del detalle que mostrara al crear un registro del Master
form_class = RekuestDetForm
_Views.py_
class RekuestCreateView(NamedFormsetsMixin, CreateWithInlinesView):
model = Rekuest
form_class = RekuestForm
template_name = "op/request_form.html"
inlines = [RekuestDetInline]
inlines_names = ['RekuestDetInline']
def get_context_data(self, **kwargs):
ctx = super(RekuestCreateView, self).get_context_data(**kwargs)
ctx['title'] = _("Create new Request")
return ctx
def get_form(self, form_class):
form = CreateWithInlinesView.get_form(self, form_class)
#Filtra los Socios de Negocio por tipo=Cliente
form.fields['bpartner'].queryset = BPartner.objects.filter(iscustomer='True')
return form
def construct_inlines(self):
#Filtra el socio de negocio del detalle por tipo=Proveedor (Aseguradora)
inlines = CreateWithInlinesView.construct_inlines(self)
RekuestDetInline = inlines[0]
RekuestDetInline.form.base_fields['bpartner_vendor'].queryset = BPartner.objects.filter(isvendor=True)
return inlines
def forms_invalid(self, form, inlines):
messages.error(
self.request,
"Your submitted data was not valid - please correct the below errors")
return super(RekuestCreateView, self).forms_invalid(form, inlines)
def forms_valid(self, form, inlines):
# Default company
#self.object.company = self.request.user.company
# Save object to recalculate totals
out = CreateWithInlinesView.forms_valid(self, form, inlines)
self.object.save()
messages.success(self.request, "Request %s saved." % (self.object.code,))
return out
_request_form.html_
<form action="." method="post" id="request_form" class="form-horizontal wysiwyg" enctype="multipart/form-data">
{% csrf_token %}
<fieldset>
<div class="well">
<legend>
Nueva Solicitud
</legend>
</div>
<table border="0" cellspacing="5" cellpadding="5">
<tr>
<td>{% trans 'Code' %}</td><td><span id="code" class="uneditable-input">{{object.code|default:''}}</span></td>
<td>{{form.orderdate.label}}</td><td>{{form.orderdate}}</td>
</tr>
<tr>
<td>{{form.bpartner.label}}</td><td>{{form.bpartner}}</td>
<td>{{form.type_owner.label}}</td><td>{{form.type_owner}}</td>
<td>{{form.policy_type.label}}</td><td>{{form.policy_type}}</td>
</tr>
<tr>
<td>{{form.concept.label}}</td><td>{{form.concept}}</td>
<td>{{form.promise_date.label}}</td><td>{{form.promise_date}}</td>
<td>{{form.status.label}}</td><td>{{form.status}}</td>
</tr>
</table>
<br/>
<fieldset class="module aligned ">
<table class="table">
<tr>
<th>{% trans 'Insurance' %}</th>
<th>{% trans 'Agent' %}</th>
<th>{% trans 'Currency' %}</th>
<th>{% trans 'Payment Term' %}</th>
<th>{% trans 'Deductible' %}</th>
<th>{% trans 'Delete' %}</th>
</tr>
{{ RekuestDetInline.management_form }}
{% for f in RekuestDetInline %}
<tr class="RekuestDetInline" id="id_{{ RekuestDetInline.prefix }}-{{forloop.counter0}}">
<td>{{f.id}}
{{f.bpartner_vendor.errors.as_ul}}{{f.bpartner_vendor}}</td>
<td>{{f.contact_name.errors.as_ul}}{{f.contact_name|add_class:"input-small"}}</td>
<td>{{f.currency.errors.as_ul}}{{f.currency|add_class:"input-small"}}</td>
<td>{{f.paymentterm.errors.as_ul}}{{f.paymentterm}}</td>
<td class="numberfield field-base"><span>{{f.deductible}}</span></td>
<td>{{f.DELETE}}</td>
</tr>
{% endfor %}
</table>
</fieldset>
</fieldset>
<button class="btn btn-primary btn-large" type="submit">{% trans "Save" %}</button>
</form>
#views
class FooCreate(CreateWithInlinesView):
model = Foo
form_class = FooForm
inlines = [BarInline]
class BarInline(InlineFormSet):
model = Bar
#forms
# No BarForm!
CreateWithInlinesView seems to be ignoring the form I created. The above code works with no error, the view will automatically generate the form based on model fields. However, if I create BarForm and add form_class = BarForm
to BarInline, I get a TypeError: metaclass conflict
.
How do I use my own form for an inline?
Tested in Django 1.4.5
class SortableListMixin(object):
# both sorting and pagination works.
....
class SortableListMixin(ContextMixin):
# breaks pagination, but sorting works.
....
class MyListView(SortableListMixin, ListView):
# Sorting works, pagination doesn't
paginate_by = 10
class MyListView(ListView, SortableListMixin):
# Pagination works, sorting doesn't
paginate_by = 10
I just added django-extra-views to DjangoPackages.com
http://djangopackages.com/packages/p/django-extra-views/
I would suggest adding a better description to your github repo that explains the real purpose of this app so others can find it more easily.
Honestly I think it needs a name like "django-formset-views" or something like that, but maybe thats a pain to move around on github.
Thanks!
For example the UpdateWithInlines
needs inlines
defined and for it to be iterable. It's much easier to spot this if there is a placeholder which is []
. Alternatively we could define it as None
and raise a helpful error, similarly to how django does if you don't define a Model
or queryset
.
In this particular case this may be helped by a get_inlines
method, which throws NotYetImplemented
if the attribute is not defined properly.
When installing using django 1.6.2 and python 3.3.5:
$ pip install django-extra-views
Downloading/unpacking django-extra-views
Downloading django-extra-views-0.6.4.tar.gz
Running setup.py (path:/py33_django16/build/django-extra-views/setup.py) egg_info for package django-extra-views
Requirement already satisfied (use --upgrade to upgrade): Django>=1.3 in /py33_django16/lib/python3.3/site-packages (from django-extra-views)
Installing collected packages: django-extra-views
Running setup.py install for django-extra-views
File "/py33_django16/lib/python3.3/site-packages/extra_views/multi.py", line 35
except ValidationError, e:
^
SyntaxError: invalid syntax
Successfully installed django-extra-views
Cleaning up...
How/Where is the management form in the context? I tried both {{ inlines.management_form }}
and {{ form.management_form }}
, but these don't work - hence the form doesn't validate.
Using the simplest case, almost directly from the documentation:
class SQDetailsInline(InlineFormSet):
model = SQDetails
fields = ('terminal','merchant',)
exclude = ('pk','id','account')
can_delete = False
fk_name = 'account'
class CreateOrderView(CreateWithInlinesView):
model = SQAccount
inlines = [SQDetailsInline]
template_name = 'enter-order.html'
def formset_valid(self,form):
print form # this is here to force a 500
Hello @AndrewIngram, no documentation was created for "multi" module because it is not usable or lack of available time to create it?
A minimal documentation for this module would be great.
I'm a little lost on the correct way to use it
nice project, thanks.
Hi!
I'm trying to implement a form with inline fields, where I have a field at my form that will be filled after the post, but it is excluded from the form. I do this at form_valid method, as described at my code bellow. I've perceived that form_valid is not woking but CreateWithInlinesView is a derivative from FormView where the method form_valid is native. Can you bring some help with this issue? Thanks so much!
class CampaignCreateView(CreateWithInlinesView):
model = Campaign
inlines = [CampaignListsInline, ScheduleProgramInline, ManualScheduledSendInline]
template_name = "campaigns/campaign/campaign_add.html"
success_url = '/campaigns/campaign/'
form_class = CampaignForm
def form_valid(self, form):
""" Associate the record to the customer """
form.instance.customer = self.request.user.get_profile().customer
return super(CampaignCreateView, self).form_valid(form)
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(CampaignCreateView, self).dispatch(*args, **kwargs)
They both use self.model which does not need to be set at all for the other cases.
I suggest adding a get_model method to the BaseFormSetMixin which tried to get the model from self.model and otherwise get's it from the self.get_queryset().model
Thus removing the need to define a queryset and a model.
The repository url is pointing to a fork of this project.
url='https://github.com/miguelrestrepo/django-extra-views',
In pypi, it's showing this one instead of yours.
Problem discovered using pep438 tool:
$ sudo pip install pep438
$ pep438 django-extra-views
โ django-extra-views: 2 URLs
Page showing extra links: http://pypi-externals.caremad.io/django-extra-views/
( please ignore, looks like my local virtualenv was messed up )
We are using a postgresql-db which has transactions.
When we run your tests against sqlite3 the above testcases work, when running against postgresql, they fail.
When we use TransactionTestCase instead of TestCase as base-class, the tests work like expected.
Even if nothing is done, SearchableListMixin adds a .distinct() to the QS. In my use case, that incurred a 58% slowdown when viewing the index page without a ?q
https://github.com/AndrewIngram/django-extra-views/blob/master/extra_views/contrib/mixins.py#L78
Is it really necessary? If it is, perhaps we could move it up a level so it's only applied if there's something to do?
Using
related_name in a ForeignKey in a model seems to break InlineFormSet
See issue:
jazzband/django-admin2#288
adding a related_name in django-admin2 causes the tests to fail.
But it should be True for UpdateWithInlinesView. Or am I confused?
Can you push your tags from releases to Github, so it's easier to see what changed between releases?
git push --tags
I'm trying to integrate extra_views in a project but I stumbled across what appears to be a bug: if I set an "extra" attribute for my class, it seems to have no effect. Curiously, I get 5 extra objects - not even the 2 extra objects that appear to be the default for BaseFormSetMixin.
Am I doing something wrong?
Just a crude starting point - the big issue here is that construct_form is called before get_context_data which is where django's multipleobjectmixin does the pagination work and modifies the queryset.
from extra_views.formsets import BaseModelFormSetView
from extra_views.compat import ContextMixin
from django.views.generic.list import MultipleObjectTemplateResponseMixin
class ModelFormSetView(MultipleObjectTemplateResponseMixin, BaseModelFormSetView):
"""
A view for displaying a model formset, and rendering a template response
"""
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
context = self.get_context_data()
return self.render_to_response(context)
def get_context_data(self, **kwargs):
"""
Get the context for this view.
"""
queryset = kwargs.pop('object_list', self.object_list)
page_size = self.get_paginate_by(queryset)
context_object_name = self.get_context_object_name(queryset)
if page_size:
paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)
formset = self.construct_formset()
context = {
'paginator': paginator,
'page_obj': page,
'is_paginated': is_paginated,
'object_list': queryset,
}
else:
context = {
'paginator': None,
'page_obj': None,
'is_paginated': False,
'object_list': queryset,
'formset': formset
}
if context_object_name is not None:
context[context_object_name] = queryset
self.queryset = queryset
context['formset'] = self.construct_formset()
return ContextMixin.get_context_data(self, **context)
Currently all forms are instantiated based on the POST data, whether or not they end get getting validated. This means that when the page is finally rendered they have empty data rather than their initial data, for example a formset will have no form rows rather than showing the real initial data.
So the way forms need to be instantiated AFTER we know what group was POSTed, so we can prevent forms outside of the group being given the data and files. At the moment we use the same approach for instantiation that we do with GET, this may need to change.
It is in your requirements.txt (six==1.5.2) but not in setup.py
Main issue I can see is that the hooks in Django related to py3k were introduced in 1.4.2, so I'd need to bump the required version of Django up to that,
Might consider merging your efforts: https://github.com/dszczyt/django-nested-forms
At the moment this library has no real documentation, and much like Django's own class-based views, it's not obvious how to use it unless you read the source code quite carefully.
Quickest solution is to come up with a list of common use cases for the views and explain how to implement them.
When trying to pip install in environment using python 3.3.3, django 1.6.2:
$ pip install django-extra-views
Downloading/unpacking django-extra-views
Downloading django-extra-views-0.6.4.tar.gz
Running setup.py (path:/.virtualenvs/py33_django16/build/django-extra-views/setup.py) egg_info for package django-extra-views
Requirement already satisfied (use --upgrade to upgrade): Django>=1.3 in /.virtualenvs/py33_django16/lib/python3.3/site-packages (from django-extra-views)
Installing collected packages: django-extra-views
Running setup.py install for django-extra-views
File "/.virtualenvs/py33_django16/lib/python3.3/site-packages/extra_views/multi.py", line 35
except ValidationError, e:
^
SyntaxError: invalid syntax
Successfully installed django-extra-views
Cleaning up...
This change is rather trivial:
except ValidationError as e:
Havent tested it yet... will it work? ๐ฑ
I was referencing this StackOverflow answer about model inline formsets.
I am trying to get my inline formset to show just the queryset I specify.
As far as I can tell, line 114 of formsets.py doesn't do what it implies it will.
class BaseInlineFormSetMixin(BaseFormSetMixin):
# ...
formset = BaseInlineFormSet
# ...
I can't find anywhere in the code where it actually uses that specified value.
I'd like to be able to use code similar to the following and have my formset class be used when using the factory:
class BaseResponseInlineFormSet(InlineFormSet):
model = Response
can_delete = False
extra = 0
formset = GenericResponseFormSet
I'm kind of confused by the purpose of the code there. Here are my possible explanations of how a solution might look (depending on the intention of the code in the first place):
My workaround for now is to pass it manually into get_factory_kwargs()
Thanks!
Great job, @AndrewIngram, django-extra-views
is a very useful piece of software. Maybe you could help me on this problem of mine in combination with django-extra-views
:
In a extra_views.CreateWithInlinesView()
I'm trying to have a custom formset validation for my inlines by overriding the clean()
method of my formset.
Apparently there should be a method non_form_errors()
on the formset but calling inlines.0.non_form_errors
in my template won't print the errors.
Maybe some dummy code might be helpful to understand this. I stripped the non-important stuff:
class MyModelInlineFormSet(django.forms.models.BaseInlineFormSet):
def clean(self):
raise django.forms.ValidationError('Foobar')
class MyModelInline(extra_views.InlineFormSet):
model = MyModel
extra = 5
formset_class = MyModelInlineFormSet
class MyCreateView(extra_views.CreateWithInlinesView):
model = MyParentModel
form_class = MyParentModelModelForm
inlines = [MyModelInline]
And here's the part about the non_form_errors()
method in the docs: https://docs.djangoproject.com/en/dev/topics/forms/formsets/#custom-formset-validation
if you do pip install -U django-extra-views , it breaks because contrib is not included. I assume it would break if you just install it, too.
if you pip install django-extra-views-ng, everything is ok.
RESULT
Internal Server Error. It could be
EXPECTED
I'm not sure what we should expect here, but definitely not uncaught generic exceptions.
Hey Andrew,
Thanks for the note - So it's working I can see the data going into the db. But the populated data is not showing back in the view.
But the view doesn't show anything. It's always empty. Do you have any pointers.
FWIW - It'a very basic example..
class CompanyDetailView(InlineFormSetView):
"""Details of the Company Page"""
model = Company
inline_model = CompanyDocument
fk_name = "company"
fields=('document', 'description')
can_delete=True
extra = 1
I suspect this has to do with the fk_name.
Hi there,
Thanks for an excellent set of views - they're very handy.
However - i don't seem to be able to get new image files to get uploaded when the forms are saved with the UpdateWithInlinesView. I suspect the contents of request.FILES isn't being bound to the model? My form definitely has an enctype="multipart/form-data" attribute.
Do you have any suggestions?
Many thanks,
Stephen
Using forms_valid()
and never calling form_valid()
means that the SuccessMessageMixin
can't set any success messages. (form_valid()
is where SuccessMessageMixin
injects the messages)
To get round this, I made a new InlineSuccessMessageMixin
from django.contrib import messages
class InlineSuccessMessageMixin(object):
"""
Adds a success message on successful form submission.
"""
success_message = ''
def forms_valid(self, form, formset):
print "something"
response = super(InlineSuccessMessageMixin, self).forms_valid(form, formset)
success_message = self.get_success_message(form.cleaned_data)
if success_message:
messages.success(self.request, success_message)
return response
def get_success_message(self, cleaned_data):
return self.success_message % cleaned_data
It's basically just a copy of the django's built in one.
If you were to implement this, things to note:
It doesn't pass the formset forms' cleaned_data
to the success message
Django's generic views fall short when you want to handle multiple forms within a single view, I want to come up with a new class-based view which makes it easy to handle this along with any handling logic that may be required.
An example use case would be the Basket view on an e-commerce site. the "Add to cart" buttons around the site should post to this view, the view should render formsets of items on GET as well as handling POST. Also needs to handle save-for-later and adding voucher codes to the basket. So we've ended up where we have 4 different kinds of date modification being performed on the same resource (the basket), using separate views for this would break the post-validate-redirect loop.
I propose an API like this:
class BasketView(MultiFormView):
forms = {
'items': MultiFormView.modelformset(model=BasketItem),
'add': MultiFormView.form(form=AddToBasketForm),
'saved': MultiFormView.modelformset(model=BasketItem),
}
def get_items_queryset(self):
return self.request.basket.lines.all()
def get_saved_queryset(self):
return self.request.saved_basket.lines.all()
def valid_items(self, form, valid_forms):
# Called when items is valid
def valid_add(self, form, valid_forms):
# etc
The form-specific methods would be called automatically using has/getattr.
Sometimes you might want two forms to be processed in the same request, so you need a way to say that they depend on each being present:
class OrderView(MultiFormView):
forms = {
'order': (MultiFormView.modelform(model=Order), dict(requires=('items')),
'items': (MultiFormView.modelformset(model=OrderItem), dict(requires=('order')),
}
def forms_valid(self, valid_forms):
# this only gets called if both 'order' and 'items' were present and both validated, happens after the post-validation handler for the individual forms.
pass
Hello, this may be out of the scope of what this application is meant to do and it's more of a feature request than an issue. First off, this package is great and it makes creating formsets a breeze, but I've hit a brick wall with dynamically adding forms to a formset. I'm not particularly good with Javascript and I'm wondering if anyone has found a decent solution to this?
Assume, for examples sake, we have a form for an album which can contain a bunch of images. Initially, we would render the album form and 5 image forms. If a user wants to add more than 5 images, they could hit a button that says 'add another' which would then render another image form.
I've found a few things around the place that hint towards how to do this, but as I said, my Javascript isn't very good and I'm terrible with regular expressions so I'm having a lot of trouble matching the form IDs and incrementing them as necessary. Thanks for any help on this :) I'll keep working with what I've got and if I make any breakthroughs I'll post them up in here.
Is it possible to do nested formsets with django-extra-views? I'm thinking of something along these lines: http://yergler.net/blog/2009/09/27/nested-formsets-with-django/ ... If it is possible, how would I do it?
A secondary question: Is it possible to have a formset with nested forms? So I have a formset of Survey objects and I want each to also render/save/update a related model of
modelformsets should provide a way to call save_m2m() when applicable, could be done using a boolean flag or maybe inspecting the fields to see if they include a manytomany relationship.
Not sure if this is a deeper problem with Django ModelForms, or just this package.
If I have a ModelFormSetView, to add Persons objects to a Trip object. I want to add some initial data to the forms, default names for each person, "Person 1", "Person 2" etc.
class AddPersonsFormSetView(ModelFormSetView):
model = Person
template_name = 'AddPersons.html'
extra = 1
success_url = '/trip/%s/expense/add/'
def get_formset_kwargs(self):
kwargs = super(AddPersonsFormSetView, self).get_formset_kwargs()
num_persons = self.kwargs['num_persons']
## inital data will give the name Person <increment>
initial = [
{ 'name' : "Person %s" % i , 'trip' : self.kwargs['trip_id'] } for i in range( 1, int(num_persons)+ 1)
]
kwargs.update({'initial': initial })
return kwargs
Now if I change the values in the form, it saves correctly. If I leave the default values as they are, the PersonForm generated by the factory does not see the data_changed() as True, so doesn't save anything.
I can work around this by creating the form, overriding the has_changed method, and specifying it in the get_factory_kwargs() method of the AddPersonFormSetView but this isn't an obvious solution until you step through the code. It doesn't not feel seem correct behaviour to ignore default values.
class PersonForm(ModelForm):
class Meta:
model=Person
def has_changed(self):
"""
Overriding this, as the initial data passed to the form does not get noticed,
and so does not get saved, unless it actually changes
"""
changed_data = super(ModelForm, self).has_changed()
return bool(self.initial or changed_data)
class AddPersonsFormSetView(ModelFormSetView):
...
...
def get_factory_kwargs(self):
kwargs = super(AddPersonsFormSetView, self).get_factory_kwargs()
kwargs['form'] = PersonForm
return kwargs
I was trying to use the non-documented "extra_views/multi.py" module, and came across this error.
AttributeError at /
type object 'UserForm' has no attribute 'get_context_suffix'
Request Method: GET
Request URL: http://127.0.0.1:8000/
Django Version: 1.6.2
Exception Type: AttributeError
Exception Value:
type object 'UserForm' has no attribute 'get_context_suffix'
Exception Location: /home/sutransdev/1envs_virtualenv/sisposto/local/lib/python2.7/site-packages/extra_views/multi.py in construct_forms, line 92
Python Executable: /home/sutransdev/1envs_virtualenv/sisposto/bin/python2.7
Python Version: 2.7.5
Python Path:
['/home/sutransdev/projetos/posto/sisposto/sisposto',
'/home/sutransdev/projetos/posto/sisposto',
'/home/sutransdev/projetos/posto/sisposto/sisposto',
'/home/sutransdev/1envs_virtualenv/sisposto/lib/python2.7',
'/home/sutransdev/1envs_virtualenv/sisposto/lib/python2.7/plat-x86_64-linux-gnu',
'/home/sutransdev/1envs_virtualenv/sisposto/lib/python2.7/lib-tk',
'/home/sutransdev/1envs_virtualenv/sisposto/lib/python2.7/lib-old',
'/home/sutransdev/1envs_virtualenv/sisposto/lib/python2.7/lib-dynload',
'/usr/lib/python2.7',
'/usr/lib/python2.7/plat-x86_64-linux-gnu',
'/usr/lib/python2.7/lib-tk',
'/home/sutransdev/1envs_virtualenv/sisposto/local/lib/python2.7/site-packages']
Server time: Qui, 3 Abr 2014 18:33:20 -0300
In ProcessMultiFormView
:
Instead of having prefixes be a list for this section:
posted_prefixes = []
# First we detect which prefixes were POSTed
for prefix in self.get_form_definitions().keys():
for field in self.request.POST:
if field.startswith(prefix):
posted_prefixes.append(prefix)
break
# Now we iterated over the groups until we find one that matches the POSTed prefixes
for label, prefixes in self.get_groups().iteritems():
if label == 'all' or list(prefixes) == posted_prefixes:
Wouldn't it make more sense to have prefixes be a set? I was debugging for an hour trying to figure out why things wouldn't work, when I figured out that the computed posted_prefixes
were something like ["left_form", "right_form"] and my group's prefixes (that it was comparing it to) were ["right_form", "left_form"]. Obviously these didn't match and I kept getting a 404 error. Using a set would solve this issue and simplify problems in the future.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.