So I have a form where I defined a select widget like this:
class AdHocVoucherTemplateForm(ModelForm):
class Meta:
model = AdHocVoucherTemplate
widgets = {
'retailer_id': Select(choices=[(r.pk, r.name) for r in Retailer.objects.all()]),
}
This way I achieve a select input field with all retailers. User can select a retailer from a drop down list and submit the form.
The problem I noticed is that when I add a new retailer (Retailer.objects.create etc), it doesn't appear in the form in the drop down list. It appears to be cached. When I restart the uwsgi service running Django, it is there.
How can I make the widget always refresh the newest values from the database?
I don't see this caching behavior when I do something similar with a ModelChoiceField.
It's default widget is a Select.
Something like:
retailer = forms.ModelChoiceField(queryset=Retailer.objects.all())
When your code is evaluated, that choices parameter is constructed once and then your select just has a static list of retailer (id,name) tuples. When the ModelChoiceField is constructed, it is referencing a QuerySet which is not evaluated until the list of choices is actually requested/displayed.
Related
I have a form (ModelForm) in Django, where I am adding a field for users in the init method as so:
self.fields["users"] = forms.ModelMultipleChoiceField(
queryset=users, widget=forms.CheckboxSelectMultiple, required=False,label="Add Designer(s)"
)
In the save method how I can iterate over the queryset for this field, however, I do not know how I can test if the particular model has been selected/checked. Help, please.
EDIT:
Let's say that you have a form where you want to be able to add users to a certain project, I set the users field as above (also usedMultipleChoiceField) but my real question is how do you determine the state of those checkboxes (which users should be added)?
Managed to fix it using MultipleChoiceField instead of ModelMultipleChoiceField. Then populated the choices with existing event IDs and passed it to the template.
In forms:
choices = forms.MultipleChoiceField(widget = forms.CheckboxSelectMultiple())
In views:
form.fields['choices'].choices = [(x.eventID, "Event ID: " + x.eventID) for x in unapproved]
Had to change some of the logic for finding and editing Event objects too.
The Django documentation states that a ModelMultipleChoiceField normalizes to a QuerySet of model instances. That means in your example, it will only return the users that have been checked. If none have been checked, it will return an empty QuerySet.
If you are overriding your ModelForm save method, you could include something like this:
selected_users = self.cleaned_data.get('users')
for user in selected_users:
project_users.add(user)
I have the following model:
class Owner(models.Model)
country = models.CharField(max_length=255, choices=COUNTRIES, default=COUNTRIES_DEFAULT)
COUNTRIES is compose of tuples:
COUNTRIES = (
('afg', 'Afghanistan'),
('ala', 'Aland Islands'),
('alb', 'Albania'),
('dza', 'Algeria'),
('asm', 'American Samoa'),
....... )
For FrontEnd, I need to show a Widget, and for each country to have a checkbox.
A Person/User can select multiple Countries.
I presume I need to use a custom widget, but I don't know where to start inherit for Field/Widget and make the query in the database.
--- Why is not a duplicate of Django Multiple Field question ----
I don't need a new Model field, or to store it in the database and is not a many to many relation, so something like the package django-multiselectfield is not useful.
The ModelField is storing just one value, but in the form will appear values from the tuple.I added just to see the correspondence.
Instead I need to be just a Form Field, to get the values, and query the database. Like get all owners that resides in USA and UK.
Also is not looking like Select2, I need to respect design. As functionality is like in the image:
In your Form you must define a MultipleChoiceField with the CheckboxSelectMultiple widget:
countries = forms.MultipleChoiceField(choices=COUNTRIES, widget=forms.CheckboxSelectMultiple)
This will give you a list of multiple choice checkboxes. You can style that yourself to appear with a scrollbar if you don't want to show a long list.
Here is an example from the Django documentation: https://docs.djangoproject.com/en/2.1/ref/forms/widgets/#setting-arguments-for-widgets
In django admin, you can add, edit, and even delete objects from another model if there is a relationship between the two.
For instance, if my code looks like this:
class Category(models.Model):
...
class Product(models.Model):
...
category = models.ForeignKey(Category)
When I am editing/adding a product using the django admin site, in the category field, I have 3 buttons to add/edit/delete categories. Adding one takes to a new window, and once I submit the form, the category is added, the window is closed, and I am returned to my product form with the extra category present. Like this:
How can I do this in my normal application (outside the admin) using forms?
If I understand your question correctly, you could do what django admin does, which is to link the add button to this:
/admin/<your_app>/<your_model>/add/?_to_field=id&_popup=1
and then it uses a bit of javascript to get back the new object you just created. If you look into the contrib/admin/static/admin/js/admin/RelatedObjectLookups.js file (in django's code), you'll see a few functions that pass the id of the calling field to the popup (in showRelatedObjectPopup), and then bring back the selected id (in dismissRelatedLookupPopup).
This is for adding a new object, but you can look into the logic for changing/deleting.
You can replicate that logic with your own forms.
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 have a model service and a ModelForm named Service which I use to add and update the service model. The model looks like this:
class Service(models.Model):
categories = models.ManyToManyField(Category)
The categories field is displayed as a tag with that allows multiple selection. It works well when I'm adding a new record but when I'm updating it, only one service is showing up on the request.POST['categories'] even if I selected multiple categories.
I tried dumping the request object and I can see that the categories is showing something like:
u'categories': [u'3', u'4', u'2']
I tried calling the request._get_post() and it did return only 1 category, hence the request.POST['categories'] returns only 1. Anybody who knows what's happening and how to fix it?
You probably want to use
request.POST.getlist('categories')
which will return all the selected values for that form field.