I've been trying to crack this nut for a while but I cannot seem to be able to set selected values for multipleselect. What I have is:
class GroupUsersForm(forms.Form):
users = forms.MultipleChoiceField()
def __init__(self, *args, **kwargs):
super(GroupUsersForm, self).__init__(*args, **kwargs)
if kwargs.has_key('initial'):
self.selected = kwargs['initial']['users']
self.choices = kwargs['initial']['all']
self.fields[self.get_field_name()] = self.get_users_field()
def get_users_field(self):
field_class = forms.MultipleChoiceField
field = field_class(
label=_(u"users"),
choices = self.get_field_choices(),
widget = FilteredSelectMultiple(_(u"users"), is_stacked= False),
#initial = self.get_field_initial(),
required= False
)
return field
def get_field_name(self):
return 'users'
def get_field_choices(self):
choices = [(p.id, p.username) for p in self.choices]
return choices
def get_field_initial(self):
selected = [(p.id, p.username) for p in self.selected]
return selected
and i initiate it like that:
uform = GroupUsersForm(initial = {'all': users, 'users':u, 'group':g,})
both users and u are querysets (
users = get_users_with_perms(a).order_by('username', 'last_name', 'first_name')
u = User.objects.filter(Q(groups = g)).order_by('username', 'last_name', 'first_name'))
which in one test case were even the same.
No selected options showed up.
I tried setting the initial values myself manually to list based of object ids, passing single id, passing (id, username) tuple and so on... tried using different widget, but all widgets display all the options but none of them are selected.
what am i doing wrong?
Alan
Try setting the choices property of the users field. The value of 'users' in the initial dict should be a list of whatever the keys are for the user choices. For example, if
self.fields['users'].choices = (
('username1','Firstname Lastname'),
('username2','Firstname Lastname'),
('username3','Firstname Lastname'),
)
Initial should be ['username1', 'username3']
Then change your form instantiation and __init__ to the following:
uform = GroupUsersForm(users, initial = {'users':u,})
def __init__(self, user_choices, *args, **kwargs):
super(GroupUsersForm, self).__init__(*args, **kwargs)
self.fields['users'].choices = user_choices
Related
I want to add an additional field to my Import-Form on the Admin page.
I did everything the Docs say but the entered values for year and calender_week wont show up.
resources.py
class ForecastListResource(resources.ModelResource):
year = fields.Field(column_name="Jahr", attribute="year")
calender_week = fields.Field(column_name="Kalenderwoche", attribute="calender_week")
brand = fields.Field(column_name="Marke", attribute="brand")
material = fields.Field(column_name="Material", attribute="material")
material_short_text = fields.Field(column_name="Materialkurztext", attribute="material_short_text")
gmc = fields.Field(column_name="GMC", attribute="gmc")
gmc_text = fields.Field(column_name="GMC Text", attribute="gmc_text")
bed_date = fields.Field(column_name="BedTermin", attribute="bed_date")
bed_amount = fields.Field(column_name="BedMenge", attribute="bed_amount")
bed_week = fields.Field(column_name="BedWoche", attribute="bed_week")
code_last_bed_week = fields.Field(column_name="Code letzte KW", attribute="code_last_bed_week")
fabric_number = fields.Field(column_name="Stoffnummer", attribute="fabric_number")
print_stage_3 = fields.Field(column_name="Druckstufe 3", attribute="print_stage_3")
average_filling = fields.Field(column_name="Mittelwert Abfüllung", attribute="average_filling")
net = fields.Field(column_name="Netto", attribute="net")
class Meta:
model = ForeCastList
use_bulk = True
skip_unchanged = True
forms.py
class ForecastDoDImportFormMixin(forms.Form):
calender_week = forms.IntegerField(label="Kalenderwoche", required=True)
year = forms.IntegerField(label="Jahr", required=True)
class ForecastDoDImportForm(ForecastDoDImportFormMixin, ImportForm):
pass
class ForecastDoDConfirmImportForm(ForecastDoDImportFormMixin, ConfirmImportForm):
pass
admin.py
#admin.register(ForeCastList)
class ForeCastList(ImportExportModelAdmin):
resource_class = ForecastListResource
def get_import_form(self):
return ForecastDoDImportForm
def get_confirm_import_form(self):
return ForecastDoDConfirmImportForm
def get_form_kwargs(self, form, *args, **kwargs):
if isinstance(form, ForecastDoDImportForm):
if form.is_valid():
kwargs.update({"calender_week": form.cleaned_data["calender_week"], "year": form.cleaned_data["year"]})
return kwargs
def get_import_data_kwargs(self, request, *args, **kwargs):
print(kwargs)
return super().get_import_data_kwargs(request, *args, **kwargs)
Import-Form
Result
-> related Part from the Doc´s:
https://django-import-export.readthedocs.io/en/latest/getting_started.html#customize-admin-import-forms
If I understand correctly, you want to select a value from a dropdown and have that inserted for all rows. This means that if there is a value for 'Jahr' in the import file, this will be ignored in favour of the value selected from the dropdown.
Setting an import field to the selection in the dropdown can be achieved by assigning the value of the dropdown onto the instance of the object to be imported as follows. (I've used the single field 'year' instead of 'Jahr' and 'Kalenderwoche' but you can update your implementation along the same lines).
class ForecastListResource(resources.ModelResource):
year = fields.Field(column_name="Jahr", attribute="year")
# (other fields removed for brevity
def after_import_instance(self, instance, new, row_number=None, **kwargs):
# override to set the value of the dropdown onto the row instance
instance.year = kwargs.get("year")
class Meta:
model = ForeCastList
use_bulk = True
skip_unchanged = True
Declare the ModelAdmin class to read the 'year' value from the form:
#admin.register(ForeCastList)
class ForeCastList(ImportExportModelAdmin):
resource_class = ForecastListResource
# other methods removed
def get_import_data_kwargs(self, request, *args, **kwargs):
form = kwargs.get('form')
if form:
return {"year": form.cleaned_data["year"]}
return dict()
I was able to complete this in the example app:
I have an inventory management app that will be serving multiple locations (called contexts in my app). When a user is logged in, their current context is stored as a value in request.sessions.
I would like users to only be able to browse and retrieve records for their own location.
I've been trying to this by filtering the queryset that is called in the form definition to populate the select dropdown, i.e.
referenced_catalog = forms.ModelChoiceField(
queryset=Inventory_unit_catalog.objects.all().filter(parent_business_unit_context_id=user_context_id),
I've tried implementing several different (but similar) approaches from various SO posts, that involve defining an init block to the form, such as:
class InventoryStockAddForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user_context_id = kwargs.pop('user_context_id', None)
super(InventoryStockAddForm, self).__init__(*args, **kwargs)
name = forms.CharField(max_length=96,widget=forms.TextInput(),required=True)
referenced_catalog = forms.ModelChoiceField(
queryset = Inventory_unit_catalog.objects.all().filter(parent_business_unit_context_id=self.user_context_id),
label = u"",
widget = ModelSelect2Widget(
model=Inventory_unit_catalog,
search_fields=['name__icontains'],
attrs={'data-placeholder': 'Select catalog...', 'data-width': '35em'},
required=False))
class Meta():
model = Inventory_unit_stock
fields = ('name',)
(Different SO answers had one way or the other.)
Then in views.py:
user_context_id = request.session.get('user_context_id')
...
add_form = InventoryStockAddForm(user_context_id=user_context_id)
I've even tried using the SessionStore per https://djangobook.com/using-sessions-views-2/:
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
s = SessionStore()
user_context_id = s['user_context_id']
but it always fails at the moment the forms.py is updated as Django validates the code and cannot find a key value at the moment of validation.
Any advice would be appreciated, thanks!
You can't access self.user_context_id inside referenced_catalog = forms.ModelChoiceField(...) - that code runs when the module is loaded, not when the form is initialised.
Instead, you should set the queryset inside the __init__ method.
class InventoryStockAddForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user_context_id = kwargs.pop('user_context_id', None)
super(InventoryStockAddForm, self).__init__(*args, **kwargs)
self.fields['referenced_catalog'].queryset = Inventory_unit_catalog.objects.all().filter(parent_business_unit_context_id=self.user_context_id)
referenced_catalog = forms.ModelChoiceField(
queryset = Inventory_unit_catalog.objects.none(),
label = u"",
widget = ModelSelect2Widget(
model=Inventory_unit_catalog,
search_fields=['name__icontains'],
attrs={'data-placeholder': 'Select catalog...', 'data-width': '35em'},
required=False))
I have a FormView from which I'd like to do a bit of form processing.
Within the form_valid() I'm trying to obtain the submitted form's values in order to instantiate a different object.
When I get the form.cleaned_data however, I am returned a dictionary of {'form field name' : 'choice label'}.
I'd like to get the value corresponding to the choice label.
Here is the FormView--the get_form_kwargs bit is simple passing custom choices to the view:
class RequestView(FormView):
form_class = RequestForm
template_name = 'profile/request.html'
success_url = '/'
def get_form_kwargs(self, *args, **kwargs):
requester_obj = Profile.objects.get(
user__username=self.request.user)
accepter_obj = Profile.objects.get(
user__username=self.kwargs.get('username'))
r_favorite_set = requester_obj.get_favorite()
a_favorite_set = accepter_obj.get_favorite()
kwargs = super().get_form_kwargs()
kwargs['your_favorite'] = r_favorite_set
kwargs['their_favorite'] = a_favorite_set
return kwargs
def form_valid(self, form):
super(RequestView, self).form_valid(form)
# I've tried get_FOO_display() extra instance method
print(form.get_your_favorite_display())
# The following will return the choice label
print(form.cleaned_data.get('your_favorite'))
Favorites.objects.create(#need form choice selections)
return redirect(self.get_success_url())
Code explanation: Within the form_valid I hope to create a different object using the selection from the submitted form.
So how do I get the submitted choice instead of the label? Is this even the proper place to do this?
edit: The Form:
class RequestForm(forms.Form):
your_favorite = forms.ChoiceField(
choices=[],
widget=RadioSelect,
required=True,
label="What would you like to exchange?"
)
their_favorite = forms.ChoiceField(
widget=RadioSelect,
required=False,
)
def __init__(self, *args, **kwargs):
your_choices = kwargs.pop('your_favorite')
their_choices = kwargs.pop('their_favorite')
super().__init__(*args, **kwargs)
self.fields['your_favorite'].choices = your_choices
self.fields['their_favorite'].choices = their_choices
edit2:
def get_favorite(self):
return (('a', self.fave1), ('b', self.fave2), ('c', self.fave3))
edit3:
...So I could've just done this all along.
def get_favorite(self):
return ((self.fave1, self.fave1), (self.fave2, self.fave2), (self.fave3, self.fave3))
BUT this causes some really funky behavior in the form. For some reason this causes a radio to be selected by default with every GET request to the form view. It will select the third choice to be selected if all the options are "None", or the first option to be selected if only the first is "None".
Anyway, this may be a question for a separate post.
I have a model say Club where we have fields like:
manager = models.ForeignKey(Users, related_name="return_manager", on_delete=models.CASCADE)
members = models.ManyToManyField(Users, related_name="return_members", blank=True)
Now I want to create a drop down in a form where I can add both the manager and members to it. I tried making two requests for Club.objects.filter(pk=mypk).members.all() and Club.objects.filter(pk=mypk).manager. I tried chain function and using '| ' operator but none worked. I think the manager is a single User and not a queryset, that is what the main problem is. Any workarounds?
One possible way getting all of the information together involves modifying your form choices.
In your view you would need to pass the choices along as context to your form.
def my_view(request, club_pk):
context = {}
context.update({
"manager": Club.objects.get(pk=club_pk).manager,
"members": Club.objects.get(pk=club_pk).members.all()
}
form = MyForm(request.POST or None, request=request, context=context)
In your form, you would need to modify the __init__ method to update your choices like so:
class MyForm(forms.Form):
all_club_members = forms.ChoiceField('Manager + Members', required=True)
def __init__(self, *args, **kwargs):
self.context = kwargs.pop('context', None)
super(MyForm, self).__init__(*args, **kwargs)
manager_tuple = [(self.context['manager'].id, self.context['manager'].display_name)]
members_tuples = [(member.id, member.display_name) for member in self.context['members']
self.fields['all_club_members'].choices = manager_tuple + members_tuples
Try this:
manager = [Club.objects.filter(pk=mypk).manager]
members = Club.objects.filter(pk=mypk).members.all()
userlist = list(manager) + list(members)
return Users.objects.filter(pk__in=userlist)
Should create a queryset of all users
as per this SO question Django Passing Custom Form Parameters to Formset im tryin to use curry to pass a dictionary of initial values to my formset.
its not working, it gives me a formset of empty values, which isn't what its supposed to do.
can anyone see if im implementing this wrong?
data = {'supplier': input_data['supplier'],}
InstanceFormSet = formset_factory(BulkAddInstanceForm, extra=int(input_data['copies']))
InstanceFormSet.form = staticmethod(curry(BulkAddInstanceForm, data))
EDIT: as requested
class BulkAddInstanceForm(forms.Form):
def __init__(self, *args, **kwargs):
super(BulkAddInstanceForm, self).__init__(*args, **kwargs)
self.fields['supplier'] = forms.ModelChoiceField(
queryset=Supplier.objects.all(),
label='Supplier',
empty_label='Select a Supplier...',
required=True,
)
self.fields['syllabus'] = forms.ModelChoiceField(
queryset=Syllabus.objects.all(),
label='Syllabus',
empty_label='Select a Syllabus...',
widget=FilterWidget(
queryset=Syllabus.objects.all(),
parent_queryset=Supplier.objects.all(),
control_name='supplier',
parent_attr='supplier',
),
required=False,
)
self.fields['venue'] = forms.ModelChoiceField(
queryset=Venue.objects.all(),
label='Venue',
empty_label='Select a Venue...',
widget=FilterWidget(
queryset=Venue.objects.all(),
parent_queryset=Supplier.objects.all(),
control_name='supplier',
parent_attr='supplier',
),
required=False,
)
start_date = NiceDateField(required=False, label='Start Date')
residential = forms.BooleanField(label='Res?', required=False)
special_offers = forms.BooleanField(label='S/O?', required=False)
manual_price = forms.IntegerField(required=False)
manual_cost = forms.IntegerField(required=False)
edit2: FAO Brandon
I have looked at the docco and it suggests to do a different thing.
formset = formset_factory(BulkAddInstanceForm, extra=int(input_data['copies']))
formset = InstanceFormSet(initial=[data, ])
which creates a formset with 'copies' amount of forms, plus another one with the data in.
if i do this
formset = InstanceFormSet(initial=[data, data])
then i get two extra forms with the data in.
so my idea is i need an iterator to add 'copies' number of dictionaries and zero the initial number of forms in the formset.
not that i know how to cod that yet!!
managed to do it with the following code:
InstanceFormSet = formset_factory(BulkAddInstanceForm, extra=0)
# build the list for populating the forms
n, datalist = 0, []
while n < int(input_data['copies']):
datalist.append(data)
print datalist
n +=1
formset = InstanceFormSet(initial=datalist)
so i create the formset, then i create a list of the data dictionaries, then populate the formset with the inital data as a list.
seems to be working so far, though i've got to work out how to collect and submit the info yet .
You would need to pick up the value you're passing in during the __init__
When I've used this in the past, I've set up the parameter as such:
class MyForm(forms.Form):
def __init__(self, data, *args, **kwargs):
self.data = data
#do whatever else I need to do with data
super(MyForm, self).__init__(*args, **kwargs)
Hope that helps you out.