Django: object not iterable - python

I want to fill my model form with initial data. However, I always receive an 'Attendee' object is not iterable. Full traceback: http://dpaste.com/0BH9MAM
When I comment this out: initial=self.object, the error disappears. However, my from is not pre-filled with any data. As I add more forms I can't work with FormMixin or UpdateForm
class AssignAttendee(SuccessMessageMixin, SingleObjectMixin, TemplateView):
template_name = 'attendees/front/assign_attendee.html'
success_message = _("Attendee has been successfully updated.")
def get_object(self):
return get_object_or_404(
Attendee,
ticket_reference=self.kwargs['ticket_reference'],
ticket_code=self.kwargs['ticket_code'],
)
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)
# def post(self, request, *args, **kwargs):
# self.object = self.get_object()
# return super().post(request, *args, **kwargs)
#cached_property
def attendee_form(self):
return AssignAttendeeForm(
prefix='attendee',
data=self.request.POST or None,
initial=self.object,
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context = {
'attendee': self.object,
'attendee_form': self.attendee_form,
}
return context
forms.py
class AssignAttendeeForm(forms.ModelForm):
class Meta:
model = Attendee
fields = (
'ticket_reference',
'first_name',
'last_name',
'company_name',
'email',
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['ticket_reference'].widget = forms.HiddenInput()
self.fields['ticket_reference'].disabled = True
for visible_field in self.visible_fields():
visible_field.field.widget.attrs['class'] = 'form-control'

You should pass a dict to Form.initial, not an object.
You are probably looking for the ModelForm.instance keyword argument, which allows updating an existing instance of a model.

Related

How to get data from forms?

How can I get data from a form (ProductCreateForm)?
If I write form = self.get_form(), then I just get a form template, where some data is selected, and some are not (select especially).
If I write form = ProductCreateForm(request.POST), then I get an error saying that the request was not found. Perhaps this is due to the fact that I set the request in get_context_data() and work with them in the __init__ method in the forms.py.
I process the data in the clean method in the forms.py.
I have the following view
class ProductsCreate(CreateView):
model = Product
form_class = ProductCreateForm
http_method_names = ['get', 'post']
def get_initial(self):
initial = super(ProductsCreate, self).get_initial()
initial['request'] = self.request
return initial
​
def get_context_data(self, *args, **kwargs):
ctx=super(ProductsCreate, self).get_context_data(*args, **kwargs)
ctx['special_form'] = SpeciallyPriceForm()
return ctx
​
def get(self, request, *args, **kwargs):
self.object = None
if kwargs.get('slug'):
category = Category.objects.filter(slug=kwargs.get('slug')).first()
self.initial.update({'category': category})
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
self.object = None
form = ProductCreateForm(request.POST) #What here?
special_form = SpeciallyPriceForm(self.request.POST)
​
if form.is_valid() and special_form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
forms
class ProductCreateForm(forms.ModelForm):
#....
​
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('initial').get('request')
super(ProductCreateForm, self).__init__(*args, **kwargs)
#...
user = self.request.user
provider = Provider.objects.filter(user=user.id).last()
self.fields['category'] = ModelMultipleChoiceField(queryset=provider.category.all())
#...
def clean(self):
cleaned_data = super(ProductCreateForm, self).clean()
cd_category = cleaned_data.get('category')
#...
​
​
class SpeciallyPriceForm(forms.ModelForm):
class Meta:
model = SpeciallyPrice
fields = ['adittional_specially_price', 'adittional_specially_number']
1.try pass request in that way
def get_initial(self):
"""
Returns the initial data to use for forms on this view.
"""
initial = super(ProductsCreate, self).get_initial()
initial['request'] = self.request
return initial
then in forms.py
def __init__(self):
kwargs.pop('initial').get('request')
Are you sure that is working at all? On init in your forms I don't see super() call so you should get an error?
Do you have problem only with category field the rest data you get properly?
Where do you pass it kwargs.pop('request') ??
You can print and check what is in self.request.POST

Django: object has no attribute 'object'

I have to implement several forms, therefore I need the combination of SingleObjectMixin, TemplateView. I always receive 'AssignAttendee' object has no attribute 'object'. Do you see why I get that error?
class AssignAttendee(SuccessMessageMixin, SingleObjectMixin, TemplateView):
template_name = 'attendees/front/assign_attendee.html'
success_message = _("Attendee has been successfully updated.")
def get_object(self):
return get_object_or_404(
Attendee,
ticket_reference=self.kwargs['ticket_reference'],
ticket_code=self.kwargs['ticket_code'],
)
#cached_property
def attendee_form(self):
return AssignAttendeeForm(
prefix='attendee',
data=self.request.POST or None,
# instance=self.attendee_contact,
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context = {
'attendee_form': self.attendee_form,
}
The problem was that it was missing:
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)

Django Update and CreateView using the same Crispy Form, Add view Error

I'm using the same crispy form for add and edit and have added a variable to so I can change the submit button text from add to edit and vice versa.
However the add view is coming up with the below error:
Traceback: (removed the in built references)
...
File "/itapp/itapp/sites/views.py" in dispatch
954. return super(AddSubnet, self).dispatch(*args, **kwargs)
...
File "/itapp/itapp/sites/views.py" in get_context_data
969. context = super().get_context_data(**kwargs)
File "/usr/local/lib/python3.6/site-packages/django/views/generic/edit.py" in get_context_data
93. kwargs['form'] = self.get_form()
File "/usr/local/lib/python3.6/site-packages/django/views/generic/edit.py" in get_form
45. return form_class(**self.get_form_kwargs())
Exception Type: TypeError at /sites/site/add_subnet/7
Exception Value: 'SubnetForm' object is not callable
im not sure as to why as the code for the form looks good to my unskilled eyes at least anyway
forms.py:
class SubnetForm(forms.ModelForm):
class Meta:
model = SiteSubnets
fields = ['subnet', 'subnet_type', 'circuit', 'device_data', 'vlan_id', 'peer_desc']
def __init__(self, *args, **kwargs):
site_id = kwargs.pop('site_id', None)
self.is_add = kwargs.pop("is_add", False)
super(SubnetForm, self).__init__(*args, **kwargs)
self.fields['circuit'].queryset = Circuits.objects.filter(site_data=site_id)
self.helper = FormHelper(self)
self.helper.form_id = 'subnet_form'
self.helper.form_method = 'POST'
self.helper.add_input(Submit('submit', 'Add Subnet' if self.is_add else 'Edit Subnet', css_class='btn-primary'))
self.helper.layout = Layout(
Div(
Div(
Field('subnet', placeholder='Subnet'),
Div('subnet_type', title="Subnet Type"),
css_class='col-lg-3'
),
Div(
Div('circuit', title='Circuit'),
Div('device_data', title="Device Data"),
css_class='col-lg-3'
),
Div(
Field('vlan_id', placeholder='VLAN ID'),
Field('peer_desc', placeholder="Peer Description"),
css_class='col-lg-3'
),
css_class='row'
)
)
Views:
class AddSubnet(CreateView):
form_class = SubnetForm(is_add=True)
template_name = "sites/subnet_form.html"
#method_decorator(user_passes_test(lambda u: u.has_perm('config.add_subnet')))
def dispatch(self, *args, **kwargs):
self.site_id = self.kwargs['site_id']
self.site = get_object_or_404(SiteData, pk=self.site_id)
return super(AddSubnet, self).dispatch(*args, **kwargs)
def get_success_url(self, **kwargs):
return reverse_lazy("sites:site_detail_subnets", args=(self.site_id,))
def form_valid(self, form):
form.instance.site_data = self.site
return super(AddSubnet, self).form_valid(form)
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs()
kwargs['site_id'] = self.site_id
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['SiteID']=self.site_id
context['SiteName']=self.site.location
context['FormType']='Add'
context['active_subnets']='class="active"'
return context
class EditSubnet(UpdateView):
model = SiteSubnets
form_class = SubnetForm
template_name = "sites/subnet_form.html"
#method_decorator(user_passes_test(lambda u: u.has_perm('config.edit_subnet')))
def dispatch(self, *args, **kwargs):
self.site_id = self.kwargs['site_id']
self.site = get_object_or_404(SiteData, pk=self.site_id)
return super(EditSubnet, self).dispatch(*args, **kwargs)
def get_success_url(self, **kwargs):
return reverse_lazy("sites:site_detail_subnets", args=(self.site_id,))
def form_valid(self, form):
form.instance.site_data = self.object.site_data
return super(EditSubnet, self).form_valid(form)
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs()
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['SiteID']=self.site_id
context['SiteName']=self.site.location
context['FormType']='Edit'
context['active_subnets']='class="active"'
return context
This is the culprit: form_class = SubnetForm(is_add=True). form_class is supposed to be what the name indicates, just the class, not an instance. Use get_form_kwargs to add initialization parameters to the form constructor call (as you already do with site_id):
class AddSubnet(CreateView):
form_class = SubnetForm # just the form CLASS
# ...
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs()
kwargs['is_add'] = True # you can set 'is_add' here
kwargs['site_id'] = self.site_id
return kwargs

How to pass a variable from a get_context_data def __init__?

There are UpdateView and ModelForm, you need to pass a variable from view to form, here is view:
class EditBranchView(UpdateView):
model = Branches
template_name = 'branches/edit.html'
form_class=EditBranchForm
def get_context_data(self, *args, **kwargs):
context = super(EditBranchView, self).get_context_data(**kwargs)
if self.request.POST:
context['form'] = EditBranchForm(self.request.POST, instance=self.object, request=self.request, pk = self.kwargs['pk'])
context['phones_form'] = BranchPhonesFormSet(self.request.POST, instance=self.object)
else:
context['form'] = EditBranchForm(instance=self.object, request=self.request, pk = self.kwargs['pk'])
context['phones_form'] = BranchPhonesFormSet(instance=self.object)
return context
and my form:
class EditBranchForm(forms.ModelForm):
regions=forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple)
owner = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Profiles.objects.all())
def __init__(self, request, pk, *args, **kwargs):
super(EditBranchForm, self).__init__(*args, **kwargs)
self.pk = pk
self.request = request
self.fields['owner'].queryset = Profiles.objects.filter(pid=self.request.user.id)
self.fields['regions'].choices = self.request.user.organization.organizationtoregion_set.all().values_list('region__id', 'region__region_name')
but it give error:
init() takes at least 3 arguments (1 given)
How should I do it? Thanks
Your argument handling in EditBranchForm.__init__ is wrong. It should be something like this:
def __init__(self, *args, **kwargs):
self.pk = kwargs.pop('pk', None)
self.request = kwargs.pop('request')
super(EditBranchForm, self).__init__(*args, **kwargs)
user = request.user
self.fields['owner'].queryset = Profiles.objects.filter(pid=user.id)
self.fields['regions'].choices = user.organization \
.organizationtoregion_set.all() \
.values_list('region__id',
'region__region_name')

How to set django many-to-many field to accept null

I am working on a python/django application. In my application there are 2 tables Store and Ad. That have many to many relation.
Class Store:
ads = models.ManyToManyField(Ad, null=True, blank=True)
Class Store:
ads = models.ManyToManyField(Ad)
I have tested it with both implementations given above but when i save my store without selecting an ad it gives me error:
ads: This field is required.
How can i set ads optional here???
View:
class StoreView(FormView):
form_class = StoreForm
success_url = "/"
template_name = 'store.html'
def __init__(self):
super(StoreView, self).__init__()
self.store = None
def get_form_kwargs(self):
kwargs = super(StoreView, self).get_form_kwargs()
kwargs['current_user'] = self.request.user
if 'store_id' in self.kwargs:
self.store = Store.objects.get(id=self.kwargs['store_id'])
kwargs['instance'] = self.store
kwargs['request'] = self.request
return kwargs
def get_context_data(self, **kwargs):
context = super(StoreView, self).get_context_data(**kwargs)
context['store_info'] = self.store
return context
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(StoreView, self).dispatch(*args, **kwargs)
def form_invalid(self, form):
return super(StoreView, self).form_invalid(form)
def form_valid(self, form):
self.object = form.save()
return super(StoreView, self).form_valid(form)
Form:
class StoreForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.fields['ads'] = forms.ModelMultipleChoiceField(
queryset=Ad.objects.filter(type=13),
widget=forms.CheckboxSelectMultiple,
label='Ads associated with this store'
)
def save(self, commit=False):
store = super(StoreForm, self).save(commit=True)
return store
class Meta:
model = Store
add required=False in definition ads field in the form. When you override a field in model form, no attributes are inherited from the model. You have to add all constraints to it like max_length, required etc.

Categories

Resources