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)
Related
Field 'id' expected a number but got <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x1024f3c70>.
This is the error message and
class ProductDetail(DetailView):
model = Product
def get_context_data(self, **kwargs):
context = super(ProductDetail, self).get_context_data()
context['related_products'] = Product.objects.filter(category=Product.category)
context['categories'] = Category.objects.all()
context['no_category_post_count'] = Product.objects.filter(category=None).count
return context
this is my views.py. A page that shows a product and related items is what I want to present. My questions are 1. Am I not allowed to bring a query set in the DetailView? 2. Then should I use ListView to do so?
You access the object with self.object, so:
class ProductDetail(DetailView):
model = Product
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['related_products'] = Product.objects.filter(
category_id=self.object.category_id
)
context['categories'] = Category.objects.all()
context['no_category_post_count'] = Product.objects.filter(
category=None
).count()
return context
or perhaps shorter:
class ProductDetail(DetailView):
model = Product
def get_context_data(self, *args, **kwargs):
return super().get_context_data(
*args,
**kwargs,
related_products=Product.objects.filter(
category_id=self.object.category_id
),
categories=Category.objects.all(),
no_category_post_count=Product.objects.filter(category=None).count()
)
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
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.
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
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')