fill formset with django raw sql query - django

I use Django formset factory and update view don't fill subform with
raw SQL query and return 'RawQuerySet' object has no attribute 'ordered'
error.
object query set fine but raw SQL query return this error.
'''python
formset = modelformset_factory(model=GiftVoucherSub,
form=GiftVoucherSubForm,
extra=0,
can_delete=True,
min_num=1,
validate_min=True,
)
formset = formset(request.POST or None,
queryset=queryset,
# initial=initial,
prefix='rlt_giftvoucher',
)'''

fixed by adding extra field to forms.py and views queryset with django object.
passanger name with autocomplete.
views
queryset = GiftVoucherSub.objects.filter(main_id=id, is_deleted=False).order_by('id')
forms
class GiftVoucherSubForm(forms.ModelForm):
passanger_id = forms.CharField(max_length=30,
required=False,
widget=forms.HiddenInput()
)
passanger_name = forms.CharField(widget=forms.TextInput(attrs={
# 'id': 'form_fatura_cari_isim',
'class': 'formset-field table-condensed clearable',
'required': 'True',
'autocomplete': 'off',
'type': 'search',
'onfocus': 'fn_search_passanger(this.id)',
}
)
)
class Meta:
model = GiftVoucherSub
fields = [
'id',
'main_request_type',
'sub_request_type',
'passanger_id',
'passanger_name',
'is_deleted',
]
def __init__(self, *args, **kwargs):
super(GiftVoucherSubForm, self).__init__(*args, **kwargs)
if self.instance.passanger_id:
extra_value = BoYolcuListesi.objects.get(usertableid=self.instance.passanger_id)
self.fields['passanger_name'].initial = extra_value.isim
self.helper = FormHelper()
self.helper.form_tag = True
for field in self.fields:
self.fields[field].widget.attrs.update({'class': 'formset-field table-condensed'})
self.fields[field].label = ''

Related

Get current user in Django modelformset_factory

I need to filter employees from same company as current user in forms.py.
But the solution I found, work only for single Formsets.
If I try to pass the request.user with modelformset_factory to generate a multiple formset, I get the following Error:
'MassnahmeForm' object has no attribute '__name__'
What can i Do?
Best regards
Bostjan
views.py:
frm = MassnahmeForm(user=request.user)
mformset = modelformset_factory(Massnahmen, form=frm, extra=mn.count())
forms.py:
class MassnahmeForm(forms.ModelForm):
id = forms.IntegerField(widget=forms.HiddenInput())
pdca = forms.IntegerField(widget=forms.HiddenInput())
status = forms.IntegerField(widget=forms.HiddenInput())
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
print(self.user)
super(MassnahmeForm, self).__init__(*args, **kwargs)
class Meta:
model = Massnahmen
widgets = {
'massnahme': forms.Textarea(attrs={'onkeyup':'resizeTextarea()', 'rows': 3, 'style': 'margin: -5px;'
'width: 100%;'
'height: 100%;'}),
'umsetzer': forms.Select(choices=users, attrs={'style': 'width: 100%;'
'margin: 0px;'
'font-size: 100%;'
'padding: 0px'}),
'termin': forms.DateInput(attrs={'class': 'flatpickr flatpickr-input active',
'placeholder': 'Termin',
'readonly': 'readonly',
'style': 'width: 100%;'
'margin: 0px;'
'font-size: 100%;'
'padding: 0px'}),
}
fields = ('massnahme','umsetzer','termin','status')
You need use the Class of the form in the modelformset_factory, not one instance. Next, you can make use of the form_kwargs parameter in the Formset.
MassnahmeFormSet = modelformset_factory(
model = Massnahme,
form = MassnahmeForm,
extra = mn.count()
)
formset = MassnahmeFormSet(form_kwargs={'user': request.user})

Django - field missing from cleaned data

I am using model form and I'm trying to bypass validation of one particular field.
I have ascertained that I need use the clean() method to bypass the field. however when im printing out the cleaned data the assigned_subnets field is not in the dictionary, it is missing
actions:
I create the assigned subnet field manually in forms.py. Then using jquery I alter that form field and add more select options to it post all the options. The additional values posted were not part of the original field choices, hence the error.
output from print:
{'site_data': None, 'switches': None, 'hostname': 'STR--RTR-01', 'template': <ConfigTemplates: STR-RTR-01>, 'model': <DeviceModel: Cisco - 4431>, 'install_date': datetime.date(2016, 5, 26), 'ospf_area': None, 'snmp_data': <SNMPData: XXXX>, 'available_subnets': <QuerySet []>}
forms.py
class DeviceForm(forms.ModelForm):
class Meta:
model = DeviceData
fields = ['site_data', 'switches', 'hostname', 'template', 'model', 'install_date','ospf_area','snmp_data']
def clean(self):
super(DeviceForm, self).clean()
print(self.cleaned_data)
if self.cleaned_data.get('assigned_subnets') in self._errors:
del self._errors['assigned_subnets']
return self.cleaned_data
def __init__(self, *args, **kwargs):
site_id = kwargs.pop('site_id', None)
device_id = kwargs.pop('device_id', None)
self.is_add = kwargs.pop("is_add", False)
super(DeviceForm, self).__init__(*args, **kwargs)
devicesubnet = Subnets.objects.filter(devicesubnets__device_id=device_id)
sitesubnet = Subnets.objects.filter(sitesubnets__site_id=site_id)
common_subnets = list(set(devicesubnet) & set(sitesubnet))
subnet_id_list = []
for s in common_subnets: subnet_id_list.append(s.id)
available_subnet_data = sitesubnet.exclude(id__in=subnet_id_list)
assigned_choices = []
devicesubnet_data = DeviceSubnets.objects.filter(device_id=device_id)
for choice in devicesubnet_data:
assigned_choices.append((choice.subnet.id,choice.subnet.subnet))
self.fields['available_subnets'] = forms.ModelMultipleChoiceField(
label='Available Subnets',
queryset=available_subnet_data,
widget = forms.SelectMultiple(
attrs = {'class': 'form-control', 'size' : '15'}
)
)
self.fields['assigned_subnets'] = forms.MultipleChoiceField(
label='Assigned Subnets',
choices=assigned_choices,
widget = forms.SelectMultiple(
attrs = {'class': 'form-control', 'size' : '15'}
)
)
self.fields['available_subnets'].required = False
self.fields['assigned_subnets'].required = False
self.helper = FormHelper(self)
self.helper.form_id = 'device_form'
self.helper.form_method = 'POST'
...
views.py
class EditDevice(UpdateView):
model = DeviceData
form_class = DeviceForm
template_name = "config/device_form.html"
#method_decorator(user_passes_test(lambda u: u.has_perm('config.edit_device')))
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(EditDevice, self).dispatch(*args, **kwargs)
def get_success_url(self, **kwargs):
return reverse_lazy("config:device_details", args=(self.site_id,))
def form_valid(self, form):
form.instance.site_data = self.site
assigned_subnets = form.cleaned_data['assigned_subnets']
print(assigned_subnets)
return super(EditDevice, self).form_valid(form)
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs()
kwargs['site_id'] = self.site_id
kwargs['device_id'] = self.object.pk
return kwargs
...
EDIT:
what im trying to do is like in the image below. I have a list of available subnets and a list of chosen (assigned) subnets.
I don think this form widget exists outside of Django admin? so Ive created the two fields manually and used jquery to move a subnet from available to assigned.
then I get the assigned subnets and update the DB. however I get the errors when I alter the assigned field

Django CreateView - How to show a related field (FK) like integer instead of select?

Hi (sorry for my bad english), i'm trying to show a form using a number input instead a select in a FK Relation on django model, but i cant make it.
The thing is that i need to fill the ID of the product manually writing the id in a input box, but django automatically makes the select form with all the products!
this is what i have in forms.py
class PurchaseForm(forms.ModelForm):
class Meta:
model = Purchase
fields = [
'date',
'supplier',
'warehouse',
]
widgets = {
'date': forms.DateInput(attrs={
'type': 'date',
}),
}
class PurchaseItemForm(forms.ModelForm):
class Meta:
model = PurchaseItem
fields = [
'product',
'quantity',
'net_purchase_price',
'sell_price',
]
widgets = {
'product': forms.NumberInput(),
}
PurchaseFormSet = inlineformset_factory(
Purchase,
PurchaseItem,
fields='__all__',
extra = 10,
)
this is my view
class PruchaseCreateView(CreateView):
template_name = 'purchases/create_purchase.html'
form_class = PurchaseForm
def get_context_data(self, **kwargs):
context = super(PruchaseCreateView, self).get_context_data(**kwargs)
if self.request.POST:
context['formset'] = PurchaseFormSet(self.request.POST)
else:
context['formset'] = PurchaseFormSet()
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['formset']
if formset.is_valid():
self.object = form.save()
formset.instance = self.object
formset.save()
return redirect(self.object.get_absolute_url())
else:
return self.render_to_response(self.get_context_data(form=form))
i try with the widget NumberInput but nothing!!! any idea?
You need to include the custom form when you call inlineformset_factory:
PurchaseFormSet = inlineformset_factory(
Purchase,
PurchaseItem,
form=PurchaseItemForm
fields='__all__',
extra = 10,
)

django admin fieldsets - adding fields of related models

I have a model Employee with a OneToOne relationship with User. I'm trying to include in the Employee admin some User fields (first_name, last_name, username, email), in order to edit those fields directly from the Employee Add/Change form, but I still haven't figured out how to do it.
I see another time do this kind of thing in a similar way, but now I have a fieldset error:
Unknown field(s) (first_name) specified for Employee. Check fields/fieldsets/exclude attributes of class EmployeeAdmin
here's the code:
# FIELDSETS
default_employee_fieldset = (
('General', {
'fields': (
('user', 'full_name',),
),
}),
# ..OTHER FIELDS NOT INCLUDED
)
finance_fields_employee_fieldset = [
('General', {
'fields': (
('full_name',),
('first_name', 'last_name')
),
}),
# ..OTHER FIELDS NOT INCLUDED
]
# ADMIN FORM
class EmployeeAdminForm(forms.ModelForm):
class Meta:
model = Employee
def __init__(self, *args, **kwargs):
super(EmployeeAdminForm, self).__init__(*args, **kwargs)
self.fields['first_name'] = forms.CharField(_('first name'), max_length=30, blank=True)
self.fields['last_name'] = forms.CharField(_('last name'), max_length=30, blank=True)
if 'instance' in kwargs:
user = kwargs['instance'].user
self.fields['first_name'].initial = user.first_name
self.fields['last_name'].initial = user.last_name
# MODEL ADMIN
class EmployeeAdmin(ExtendedAdmin):
list_display = ('user', 'department', 'line_manager', 'acting_line_manager', 'jobtitle', 'office', 'payroll_id',)
search_fields = ('user__username', 'user__first_name', 'user__last_name',
'line_manager__user__first_name', 'line_manager__user__last_name')
list_filter = ('department', 'grade', 'clearance', 'office', 'user__is_active', 'user__is_staff',
'ready_for_paid_work')
fieldsets = default_employee_fieldset
def changelist_view(self, request, extra_context=None):
extra_context = {'title': 'Employee details'}
return super(EmployeeAdmin, self).changelist_view(request, extra_context)
def change_view(self, request, object_id, form_url='', extra_context=None):
if object_id:
try:
record = Employee.objects.get(id=object_id)
extra_context = {'title': 'Edit employee record: %s' % (str(record),)}
except (ValueError, Employee.DoesNotExist):
pass
# Generate a new CSRF token as this page contains sensitive data
rotate_token(request)
return super(EmployeeAdmin, self).change_view(request, object_id, form_url, extra_context)
def queryset(self, request):
qs = super(EmployeeAdmin, self).queryset(request)
if request.user.is_superuser:
return qs
elif request.user.has_perm('myapp.change_all_employees'):
if request.user.has_perm('myapp.change_ex_employees'):
return qs.filter(user__is_staff=True)
else:
return qs.filter(user__is_staff=True, user__is_active=True)
else:
return qs.filter(user__is_staff=True, user__is_active=True).filter(
Q(line_manager=request.user.employee) |
Q(acting_line_manager=request.user.employee) |
Q(user=request.user)
)
def get_form(self, request, obj=None, *args, **kwargs):
self.form = EmployeeAdminForm
if obj:
if request.user.has_perm('myapp.change_hr_employee_data'):
self.readonly_fields = ('user', )
self.exclude = None
self.fieldsets = finance_fields_employee_fieldset
elif request.user.has_perm('myapp.change_employee_data_operations'):
if request.user == obj.user:
# set readonly fields
self.exclude = None
self.fieldsets = finance_fields_employee_fieldset
else:
# set readonly fields
self.exclude = ('employer_pension_contribution', 'employee_pension_contribution',)
self.fieldsets = default_employee_fieldset
else:
# if user is in AAA department and not employee's linemanager and not own record
if request.user.employee.department == settings.DPTS['AAA']
if request.user == obj.user:
# set readonly fields
else:
# set readonly fields
self.exclude = ('account_number', 'sort_code', 'salary',
'employer_pension_contribution', 'employee_pension_contribution',)
self.fieldsets = default_employee_fieldset
else:
# if user is editing his own record
if request.user == obj.user:
# set readonly fields
self.exclude = ('account_reference', 'payroll_id',)
self.fieldsets = finance_fields_employee_fieldset[0:-2]
# if user is editing some for whom is line manager
else:
if request.user.employee == obj.line_manager or \
request.user.employee == obj.acting_line_manager:
# set readonly fields
self.fieldsets = default_employee_fieldset
self.exclude = ('employer_pension_contribution', 'employee_pension_contribution',)
else:
self.readonly_fields = ()
self.exclude = ()
self.fieldsets = default_employee_fieldset
form = super(EmployeeAdmin, self).get_form(request, *args, **kwargs)
form.request = request
return form
def save_model(self, request, obj, form, change):
if change:
old_obj = Employee.objects.get(id=obj.id)
if obj.jobtitle != old_obj.jobtitle:
employee_detail_change_notification(obj, 'job title', obj.jobtitle.name)
if obj.line_manager != old_obj.line_manager:
employee_detail_change_notification(obj, 'line manager', obj.line_manager)
if obj.acting_line_manager != old_obj.acting_line_manager:
employee_detail_change_notification(obj, 'acting line manager', obj.acting_line_manager)
if obj.home_address_line1 != old_obj.home_address_line1 or \
obj.home_address_line2 != old_obj.home_address_line2 or\
obj.home_address_line3 != old_obj.home_address_line3 or\
obj.home_address_city != old_obj.home_address_city or\
obj.home_address_postcode != old_obj.home_address_postcode or\
obj.home_address_country != old_obj.home_address_country or\
obj.home_address_phone != old_obj.home_address_phone or\
obj.personal_email != old_obj.personal_email:
new_address = '%s\n%s\n%s\n%s\n%s\n%s\n\nPhone: %s\nEmail: %s' %(
obj.home_address_line1,
obj.home_address_line2,
obj.home_address_line3,
obj.home_address_city,
obj.home_address_postcode,
obj.get_home_address_country_display(),
obj.home_address_phone,
obj.personal_email,
)
employee_detail_change_notification(obj, 'home address details', new_address)
if obj.marital_status != old_obj.marital_status:
employee_detail_change_notification(obj, 'marital_status', obj.get_marital_status_display())
obj.save()
admin.site.register(Employee, EmployeeAdmin)
Any help on this?
The reason Admin doesn't find user_name is that the user_name field isn't defined on your custom form at class level. It is only defined in __init__. When the admin inspects the form for available fields it has access only to the class, not an initialized form. So inspecting the form class doesn't show that user_name is available.
Define all the fields directly on class level instead of the form's __init__ method. If you don't need all the fields for all cases, then delete fields as needed from the form's fields dictionary in the __init__ method as needed.
You could maybe also do this in the reverse direction - adding Employee information to User edit page? This can be done as documented in https://docs.djangoproject.com/en/1.4/topics/auth/#adding-userprofile-fields-to-the-admin.
Finally, it seems you are reaching the stage where it might be easier to implement the features you want without using Admin - while Django's Admin does have a lot of extensibility features, at some point writing your own implementation will be easier than using Admin.

How to set default values in TabularInline formset in Django admin

How to set first default rows/values in django admin's inline?
class Employee(models.Model):
username = models.CharField(_('Username'), max_length=150, null=False, blank=False)
email = models.CharField(_('Email'), max_length=150, null=False, blank=False)
class Details(models.Model):
employee = models.ForeignKey(Employee, verbose_name=_('Employee'), blank=False, null=False)
label = models.CharField(_('Label'), max_length=150, null=False, blank=False)
value = models.CharField(_('Value'), max_length=150, null=False, blank=False)
class DetailsFormset(forms.models.BaseInlineFormSet):
def __init__(self, *args, **kwargs):
self.initial = [
{ 'label': 'first name'},
{'label': 'last name'},
{'label': 'job',}]
super(DetailsFormset, self).__init__(*args, **kwargs)
class DetailsInline(admin.TabularInline):
model = Details
formset = DetailsFormset
fieldsets = [
['', {'fields': ['employee', 'label', 'value']}]
]
class EmployeeAdmin(admin.ModelAdmin):
inlines = [DetailsInline]
but this row doesn't work
self.initial = [
{ 'label': 'first name'},
{'label': 'last name'},
{'label': 'job',}]
How do I set default values using django admin?
from django.utils.functional import curry
class DetailsInline(admin.TabularInline):
model = Details
formset = DetailsFormset
extra = 3
def get_formset(self, request, obj=None, **kwargs):
initial = []
if request.method == "GET":
initial.append({
'label': 'first name',
})
formset = super(DetailsInline, self).get_formset(request, obj, **kwargs)
formset.__init__ = curry(formset.__init__, initial=initial)
return formset
From here: Pre-populate an inline FormSet?
If what you need is to define default values for the new forms that are created you can redefine the empty_form property of a InlineFormSet:
class MyDefaultFormSet(django.forms.models.BaseInlineFormSet):
#property
def empty_form(self):
form = super(MyDefaultFormSet, self).empty_form
# you can access self.instance to get the model parent object
form.fields['label'].initial = 'first name'
# ...
return form
class DetailsInline(admin.TabularInline):
formset = MyDefaultFormSet
Now, every time you add a new form it contains the initial data you provided it with. I've tested this on django 1.5.
I tried many suggestions from Stackoverflow (Django=4.x), not working for me.
Here is what I did.
class MilestoneFormSet(forms.models.BaseInlineFormSet):
model = Milestone
def __init__(self, *args, **kwargs):
super(MilestoneFormSet, self).__init__(*args, **kwargs)
if not self.instance.pk:
self.initial = [
{'stage': '1.Plan', 'description': 'Requirements gathering', },
{'stage': '2.Define', 'description': 'Validate requirement', },
]
class MilestoneInline(admin.TabularInline):
model = Milestone
formset = MilestoneFormSet
def get_extra(self, request, obj=None, **kwargs):
extra = 0 #default 0
if not obj: #new create only
extra = 2 #2 records defined in __init__
return extra
I hope this works for everyone.
To provide a static default for all instances in the inline, I found a simpler solution that just sets it in a form:
class DetailsForm(django_forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['label'] = 'first_name'
class DetailsInline(admin.TabularInline):
form = DetailsForm
# ...
I think this doesn't work for the OP's particular case because each form has a different value for the 'label' field, but I hope it can be useful for anyone coming to this page in the future.