I have a cms-like page where users can create their own simple pages, with a title, image and some content. The form I'm using for it is the following:
class PageForm(forms.Form):
"""
Helper form for the cms backoffice page.
"""
title = forms.CharField(max_length=50)
preview_image = forms.ImageField(required=False)
content = forms.CharField(widget=TinyMCE(attrs={'cols': 20, 'rows': 10}))
But now I want to enhance this by adding multiple sections to a page. The thing is these are optional, so user can choose to only leave one section, in which case this form should do it, but then have a button 'add section' or something which can will add an extra TinyMCE and ImageField to the UI, also Delete section will delete one.
Now the way I see it this is a long shot, but is there any way I could model this using django forms? The way I'm thinking now if I limit the number of forms to a given number, I could add content_i and preview_image_i to the form and then check which one were submitted. That should work right? Is there any way to do it without a maximum number of sections? Otherwise how much of an overhead would I be adding if I add 100 CharFields / ImageFields which would be used rarely to a full extent (if at all).
Or should I just abandon django forms for this and do some custom handling?
Thanks
Related
I am working on a project, I have a requirement from my client he wants to implement a dynamic paginator in django admin panel. Requirement is when user input 10, ten record will display per page same for 20,30
is there any way to do it.
See ModelAdmin.list_per_page. The default is 100 but you can change it to whatever you like.
class UserAdmin(admin.ModelAdmin):
model = User
list_per_page = 5 # No of records per page
admin.site.register(UserAdmin)
If you want to dynamically change it I'd assume you'd use an ajax with a GET for the page number otherwise you'd have to do a lot more and alter the default admin template used by django.
Check out this approach if it helps you .
I am using materializecss to give my django site some material elements. I have put together a form (the 'old' way using html) but now realised I need to use a django form instead. The problem is, these forms don't play well with materialises built in column system (they use classes to determine rows and column spacing). Here is an example of the layout I set up so far. However when defining the form through form.py, it spits out one input per layer.
My question is: what can I do to either a) get django to work with the html-defined form or b) make a 'form template' to give the input fields the appropriate classes?
If you want to see the code I can post some but I'm quite a new coder so it's messy.
Thanks!
There are three ways I can think of off the top of my head.
If you want full control over the HTML form, in a Django template or HTML form, simply map the names of your fields to match the underlying field names in the Django form. This way, when POSTed back to your view, Django will automatically link up the POSTed fields with the Django form fields.
For example, if you have a field username in your Django form (or Django model if using ModelForm), you could have an element <input type="text" name="username" maxlength="40"> (that you can style any way you need) on your HTML form that Django will happily parse into your Django form field, assuming your view is plumbed correctly. There is an example of this method in the Django documentation.
Another way is to customize the Django form field widgets in your Django form definition. The Django documentation talks a little bit about how to do this. This is great for one offs, but is probably not the best approach if you expect to reuse widgets.
The final approach would be to subclass Django form field widgets to automatically provide whatever attributes you need. For example, we use Bootstrap and have subclassed nearly all of the widgets we use to take advantage of Bootstrap classes.
class BootstrapTextInput(forms.TextInput):
def __init__(self, attrs=None):
final_attrs = {'class': 'form-control'}
if attrs is not None:
final_attrs.update(attrs)
super().__init__(attrs=final_attrs)
Then it's simply a matter of letting the Django form know which widget to use for your form field.
class UsernameForm(forms.ModelForm):
class Meta:
model = auth.get_user_model()
fields = ['username']
widgets = {'username': BootstrapTextInput()}
Hope this helps. Cheers!
I'd like to create a confirmation page for selected objects before a change is made to them (outside the admin). The objects can be of different models (but only one model a time).
This is much like what is done in administration before deletion. But the admin code is complex and I haven't grasped how it is done there.
First I have severall forms that filter the objects differently and then I pass the queryset to the action / confirmation page. I have created a form factory so that I can define different querysets depending on model (as seen in another similiar question here at Stackoverflow):
def action_factory(queryset):
''' Form factory that returns a form that allows user to change status on commissions (sale, lead or click)
'''
class _ActionForm(forms.Form):
items = forms.ModelMultipleChoiceField(queryset = queryset, widget=forms.HiddenInput())
actions = forms.ChoiceField(choices=(('A', 'Approve'), ('D' ,'Deny'), ('W' ,'Under review'), ('C' ,'Closed')))
return _ActionForm
Which I use in my view:
context['form']=action_factory(queryset)()
The problem is that the items field wont be displayed at all in the html-code when it is hidden. When I remove the HiddenInput widget it displays the form correctly.
I don't want to display the choice field since there can be thousands of objects. All I want to have is something like "Do you want to change the status of 1000 objects" and a popdown and a submit button. A simple enough problem it seems, but I can't get it to work.
If someone has a solution to my current attempt I would be glad to hear how they have done it. Even better would be if there is a cleaner and better solution.
I used the wrong widget. It should be MultipleHiddenInput not HiddenInput.
I want to add same django form instance on same template. i already add one before and other add dynamically using javascript.
for example 'form" is a django form: newcell.innerHTML = {{ form.firstname }};
The problem is that when i submit the form, in view the request object has only one value (that is not add using javascript). how can i get the values of other form elements values that is added dynamically runtime.
It is something like the "Attach Another File" feature in gmail, where the user is presented with a file upload field and new fields are added to the DOM on the fly as the user clicks to "Attach Another File" plus button
You could always try separating out your FileField into a FileModel.
Take a look at the following pseudo code (as in python based on memory--i've moved over to clojure for now).
models.py
class FileModel(models.Model):
file = models.FileField()
...
class ThingToWhichYoureAttaching(models.Model):
name = models.CharField()
attachments = models.ManyToManyField(FileModel)
...
forms.py
class FileForm(forms.ModelForm):
class Meta:
model=FileModel
class ThingForm(forms.ModelForm):
attachments = forms.MultipleChoiceField()#override the manytomany form field with style field of your choice.
class Meta:
model=ThingToWhichYoureAttaching
When they pop up the window with the PLUS button, show the FileForm but on the main page leave the ThingForm untouched. You can also have an initial FileField on the main page with the ThingForm for people who don't have javascript. Just make sure to process the FileForm BEFORE the ThingForm so that the File is available for the Thing.
When processing the popup form you can use AJAX (i recommend jquery) to submit the FileForm to the server, and return the markup to insert the File in the Attachments field.
This is a follow-up on How do you change the default widget for all Django date fields in a ModelForm?.
Suppose you have a very large number of models (e.g. A-ZZZ) that is growing with the input of other developers that are beyond your control, and you want to change the way all date fields are entered (i.e. by using jQueryUI). What's the best way to ensure that all date fields are filled out using that new widget?
One suggestion from the cited question was:
def make_custom_datefield(f):
if isinstance(f, models.DateField):
# return form field with your custom widget here...
else:
return f.formfield()
class SomeForm(forms.ModelForm):
formfield_callback = make_custom_datefield
class Meta:
# normal modelform stuff here...
However, is this possible to do where you don't have explicit ModelForm's, but url patterns come from models directly? i.e. your url config is likeso:
url(r'^A/?$', 'list_detail.object_list', SomeModelA)
where SomeModelA is a model (not a form) that's turned into a ModelForm by Django in the background.
At present in my system there are no Forms for each Model. The only point of creating forms explicitly would be to add the formfield_callback suggested in the prior solution, but that goes against DRY principles, and would be error prone and labour intensive.
I've considered (as suggested in the last thread) creating my own field that has a special widget and using that instead of the builtin. It's not so labour intensive, but it could be subject to errors (nothing a good grep couldn't fix, though).
Suggestions and thoughts are appreciated.
It sounds like you want to do this project-wide (ie: you're not trying to do this in some cases, but in ALL cases in your running application).
One possibility is to replace the widget attribute of the DateField class itself. You would need to do this in some central location... something that is guaranteed to be loaded by every running instance of the django app. Middleware can help with this. Otherwise, just put it in the __init__ file of your app.
What you want to do is re-assign the widget property for the forms.DateField class itself. When a new DateField is created, Django checks to see if the code specifies any particular widget in the field property definition. If not, it uses the default for DateField. I'm assuming that if a user in your scenario really defined a particular widget, you'd want to honour that despite the change to your global API.
Try this as an example of forcing the default to some other widget... in this case a HiddenInput:
from django import forms
forms.DateField.widget = forms.HiddenInput
class Foo(forms.Form):
a = forms.DateField()
f = Foo()
print f.fields['a'].widget
# results in <django.forms.widgets.HiddenInput object at 0x16bd910>