Looping Initial Data for Formset Django - django

I want to set initial data at formset for TimeField's field every 1 hour as much 24.
So the desired output: 00:00, 01:00, 02:00, 03:00,..., 22:00, 23:00 like below image:
I tried following code but no result:
profiles = UserProfile.objects.filter(username=username)
initial_formset = [{
'user': item.name,
'time': datetime.datetime.now(). + datetime.timedelta(hours=1),
}
for item in profiles]
MyFormset = formset_factory(MyForm, extra=24)
formset = MyFormset(initial=initial_formset)
Any help will be appreciated.
*Update for request:
Forms.py:
class TestBaseFormSet(BaseFormSet):
def get_form_kwargs(self, index):
kwargs = super().get_form_kwargs(index)
kwargs['custom_kwarg'] = index
return kwargs
class MyForm(forms.Form):
user = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'class': "form-control"}))
date = forms.DateField(required=False, label="", initial=get_today, input_formats=settings.DATE_INPUT_FORMATS, widget=DatePickerInput(format="%d/%m/%Y", attrs={'class': "form-control"}))
time = forms.TimeField(required=False, label="", input_formats=settings.TIME_INPUT_FORMATS, widget=TimePickerInput(format="%H:%M", attrs={'class': "form-control"}))
def __init__(self, *args, **kwargs):
custom_kwarg = kwargs.pop('custom_kwarg')
super().__init__(*args, **kwargs)
self.fields['time'].initial = datetime.datetime.now() + datetime.timedelta(hours=custom_kwarg)
Views.py:
def create(request, username):
profiles = get_object_or_404(UserProfile, username=username)
MyFormSet = formset_factory(MyForm, extra=24, formset=TestBaseFormSet)
if request.method == 'POST':
formset = MyFormSet(request.POST or None)
if formset.is_valid():
for item in formset:
profile = MyModel()
profile.user = profiles
profile.date = item.cleaned_data['date']
profile.time = item.cleaned_data['time']
profile.save()
return redirect('home')
else:
messages.warning(request, formset.errors)
else:
formset = MyFormset()
context = {
'profiles': profiles,
'formset': formset,
}
return render(request, 'index.html', context)

Define a Baseformset class for your formset. Import BaseFomrmSet from Django.forms
class TestBaseFormSet(BaseFormSet):
def get_form_kwargs(self, index):
kwargs = super().get_form_kwargs(index)
kwargs['custom_kwarg'] = index
return kwargs
MyFormset = formset_factory(MyForm, extra=24,formset=TestBaseFormSet)
class MyForm(forms.Form):
time_field = forms.DateTimeField()
def __init__(self,*args,**kwargs):
custom_kwarg = kwargs.pop('custom_kwarg')
super().__init__(*args, **kwargs)
self.fields['time_field'].initial = datetime.datetime.now() + datetime.timedelta(hours=custom_kwarg)

Related

prepoluate a generec createview

i want that a form is prepoluate with data
my model:
TYPE = (("S",'Swing'),
("R","Rapide"))
class valuation(models.Model):
stock = models.ForeignKey("stock",on_delete=models.CASCADE,related_name='valuation',)
date = models.DateField(auto_created=True)
val_type = models.CharField(choices=TYPE, max_length=1,default='R')
user = models.ForeignKey("users.User", on_delete=models.CASCADE)
def __str__(self):
return f"{self.stock} - {self.date} - {self.val_type}"
my view:
class valuationCreateviewSwing(CreateView):
template_name = "evaluation/evaluation_create.html"
form_class = valuationModeform
def get_form_kwargs(self): # prepopulate form
kwargs = super(valuationCreateviewSwing, self).get_form_kwargs()
stck = get_object_or_404(stock, pk=self.kwargs['pk'])
kwargs['user'] = self.request.user
kwargs['val_type'] = "S"
kwargs['stock'] = stck
return kwargs
def get_context_data(self, **kwargs):
# we need to overwrite get_context_data
# to make sure that our formset is rendered
data = super().get_context_data(**kwargs)
if self.request.POST:
data["val_detail"] = ChildFormset1(self.request.POST)
else:
data["val_detail"] = ChildFormset1()
data.update({
"typeVal": "Swing",})
return data
def form_valid(self, form):
context = self.get_context_data()
val_detail_Swing = context["val_detail_Swing"]
self.object = form.save(commit=False)
# add data info neede about valuation model
self.object = form.save()
if val_detail_Swing.is_valid():
val_detail_Swing.instance = self.object
val_detail_Swing.save()
return super().form_valid(form)
def get_success_url(self):
return reverse("stock:stock-list")
I've a child form in my view (this part works ok):
ChildFormset1 = inlineformset_factory(
valuation, val_detail_Swing, form=valuationSwingModelform, can_delete=False)
I tried to use ge_for_kwargs but it seems not working as I've an error message :
init() got an unexpected keyword argument 'user'
You can use get_initial() method:
class valuationCreateviewSwing(CreateView):
template_name = "evaluation/evaluation_create.html"
form_class = valuationModeform
def get_initial(self):
query = self.request.GET
return {
'user': self.request.user.pk
'val_type': "S",
'stock': self.kwargs.get('pk')
}
...
Or you should override __init__() method and stay to use get_form_kwargs()
class valuationModeform(ModelForm):
class Meta:
model = Valuation
fields = '__all__'
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
val_type = kwargs('val_type', None)
stock = kwargs.pop('stock', None)
super().__init__(*args, **kwargs)
# assign initial values
self.fields['user'].initial = user
self.fields['val_type'].initial = val_type
self.fields['stock'].initial = stock

Validating a formset using data from another form

I'm having to do some validation across both a form and formset. The £££ amount in the form must equal the sum of the amounts in the formset.
After a lot of Googling I found a solution where I add a custom init to the baseformset as follows:
class BaseSplitPaymentLineItemFormSet(BaseFormSet):
def __init__(self, cr=None, *args, **kwargs):
self._cr = cr
super().__init__(*args, **kwargs)
def clean(self):
if any(self.errors):
return
sum_dr = 0
for form in self.forms:
sum_dr += form.cleaned_data.get('dr')
if sum_dr != float(self._cr):
raise forms.ValidationError('The amount entered needs to equal the sum of the split payments.')
I then pass the amount value from the form when the formset is instantiated, so that the value can be used in the formset validation:
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)
This worked great for the create_new view which uses formset_factory(). This morning I wrote the update view using inline_formsetfactory(), but I now get an error:
__init__() got an unexpected keyword argument 'instance'
I only have a basic understanding of how the custom init works, so I can't find a solution to this error.
Forms.py:
class SplitPaymentForm(forms.Form):
date = forms.DateField(widget=DateTypeInput())
account = GroupedModelChoiceField(queryset=Ledger.objects.filter(coa_sub_group__type='a').order_by('coa_sub_group__name','name'), choices_groupby = 'coa_sub_group')
store = forms.CharField(required=True)
amount = forms.DecimalField(decimal_places=2)
class SplitPaymentLineItemForm(ModelForm):
ledger = GroupedModelChoiceField(queryset=Ledger.objects.all().order_by('coa_sub_group__name', 'name'), choices_groupby = 'coa_sub_group', empty_label="Ledger", required=True)
project = forms.ModelChoiceField(queryset=Project.objects.filter(status=0), empty_label="Project", required=False)
class Meta:
model = LineItem
fields = ['description','project', 'ledger','dr',]
# This init disallows empty formsets
def __init__(self, *arg, **kwarg):
super(SplitPaymentLineItemForm, self).__init__(*arg, **kwarg)
self.empty_permitted = False
class BaseSplitPaymentLineItemFormSet(BaseFormSet):
def __init__(self, cr=None, *args, **kwargs):
self._cr = cr
super().__init__(*args, **kwargs)
def clean(self):
if any(self.errors):
return
sum_dr = 0
for form in self.forms:
sum_dr += form.cleaned_data.get('dr')
if sum_dr != float(self._cr):
raise forms.ValidationError('The amount entered needs to equal the sum of the split payments.')
Views.py:
def split_payments_new(request):
LineItemFormSet = formset_factory(SplitPaymentLineItemForm, formset=BaseSplitPaymentLineItemFormSet, extra=2)
if request.method == 'POST':
form = SplitPaymentForm(request.POST)
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)
if form.is_valid() and lineitem_formset.is_valid():
q0 = JournalEntry(user=request.user, date=form.cleaned_data['date'], type="SP",)
q1 = LineItem(journal_entry=q0, description=form.cleaned_data['store'], ledger=form.cleaned_data['account'], cr=form.cleaned_data['amount'])
q0.save()
q1.save()
for lineitem in lineitem_formset:
q2 = LineItem(journal_entry=q0,description=lineitem.cleaned_data.get('description'),ledger=lineitem.cleaned_data.get('ledger'),project=lineitem.cleaned_data.get('project'),dr=lineitem.cleaned_data.get('dr'))
q2.save()
messages.success(request, "Split payment successfully created.")
return HttpResponseRedirect(reverse('journal:split_payments_show_detail', kwargs={'pk': q0.id}) )
else:
form = SplitPaymentForm(initial = {'date': datetime.date.today().strftime('%Y-%m-%d')})
lineitem_formset = LineItemFormSet()
return render(request, 'journal/split_payments_new.html', {'form': form, 'formset': lineitem_formset})
def split_payments_update(request, pk):
journal_entry = get_object_or_404(JournalEntry, pk=pk, type="SP")
lineitem = LineItem.objects.get(journal_entry=journal_entry.id, dr__isnull=True)
initial = {
'date': journal_entry.date.strftime('%Y-%m-%d'),
'account': lineitem.ledger,
'store': lineitem.description,
'amount': lineitem.cr,
}
form = SplitPaymentForm(initial=initial)
LineItemFormSet = inlineformset_factory(JournalEntry, LineItem, form=SplitPaymentLineItemForm, formset=BaseSplitPaymentLineItemFormSet, extra=0)
lineitem_formset = LineItemFormSet(instance=journal_entry)
if request.method == 'POST':
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST, instance=journal_entry)
form = SplitPaymentForm(request.POST)
if lineitem_formset.is_valid() and form.is_valid():
lineitem_formset.save()
journal_entry.date = form.cleaned_data['date']
lineitem.ledger = form.cleaned_data['account']
lineitem.description = form.cleaned_data['store']
lineitem.cr = form.cleaned_data['amount']
journal_entry.save()
lineitem.save()
messages.success(request, "Split payment successfully updated.")
return HttpResponseRedirect(reverse('journal:split_payments_show_detail', kwargs={'pk': journal_entry.id}) )
return render(request, 'journal/split_payments_update.html',{'form': form, 'formset': lineitem_formset, 'journal_entry': journal_entry})
Solved. Just had to use BaseInlineFormSet.

how we save form through Class Based Generic View in django

i am using class based generic view in my Subject_En roll application
my view.py is
cc = 0
#login_required
def add_subject_enroll(request):
user = request.user
obj = StudentRegistration.objects.get(user=user)
print "obj.first_name",obj.first_name
first_name = obj.first_name
print "first_name",first_name
if obj.user:
print "object exist"
#form = Subject_EnrollForm(request.POST or None, initial={'student_name' : first_name})
#form = Subject_EnrollForm( initial={'student_name' : obj.first_name})
form = Subject_EnrollForm(request.POST or None, request.FILES or None)
form.fields["student_name"].initial = first_name
form.fields["birth_place"].initial = obj.birth_place
form.fields["gender"].initial = obj.gender
form.fields["phone"].initial = obj.phone
form.fields["email"].initial = obj.email
form.fields["phone"].initial = obj.phone
form.fields["nationality"].initial = obj.nationality
form.fields["religion"].initial = obj.religion
form.fields["blood_group"].initial = obj.blood_group
form.fields["nationality"].initial = obj.nationality
form.fields["nationality"].initial = obj.nationality
form.fields["nationality"].initial = obj.nationality
form.fields["nationality"].initial = obj.nationality
else:
print "object not found"
Subject_EnrollForm(request.POST or None, request.FILES or None)
if request.POST:
if form.is_valid():
a = form.save()
a.user = request.user
a.save()
#user.save()
messages.add_message(request,messages.SUCCESS, "your Profile was added")
#return HttpResponseRedirect('/app/all')
return HttpResponseRedirect('/')
args = {}
args.update(csrf(request))
args['form'] = form
context = RequestContext(request,
{'request': request,
'user': request.user,
'form': form})
return render_to_response('subject_enroll/add_subject_enroll.html', args, context)
class Subject_EnrollListView(ListView):
"""View to display all published and visible news entries."""
template_name = "subject_enroll/subject_enroll_list.html"
def get_queryset(self):
return Subject_Enroll.objects.all()
class DetailViewMixin(object):
"""Mixin to handle different DetailView variations."""
model = Subject_Enroll
#slug_field = 'translations__slug'
def get_queryset(self):
#return Subject_Enroll.objects.all()
return Subject_Enroll.objects.lang(self.request, False)
class Subject_EnrollDetailView(DetailViewMixin, DetailView):
def get_context_data(self, **kwargs):
context = super(Subject_EnrollDetailView, self).get_context_data(**kwargs)
context['subject_enrolls'] = Subject_Enroll.objects.all()
return context
class Subject_EnrollUpdateView(UpdateView):
form_class = Subject_EnrollForm
model = Subject_Enroll
template_name = 'subject_enroll/subject_enroll_detail.html'
def get(self, request, **kwargs):
self.object = Subject_Enroll.objects.get(id=self.request.id)
form_class = self.get_form_class()
form = self.get_form(form_class)
context = self.get_context_data(object=self.object, form=form)
return self.render_to_response(context)
def get_object(self, queryset=None):
obj = Subject_Enroll.objects.get(id=self.kwargs['id'])
return obj
i try with pass form in context of Detilviewmixin
class DetailViewMixin(object):
"""Mixin to handle different DetailView variations."""
model = Subject_Enroll
#slug_field = 'translations__slug'
def get_context_data(self, **kwargs):
context = super(DetailViewMixin, self).get_context_data(**kwargs)
#context['form'] = Subject_EnrollForm
#context['form'] = Subject_EnrollForm()
return context
def get_queryset(self):
#return Subject_Enroll.objects.all()
return Subject_Enroll.objects.lang(self.request, False)
in that form are render on template but when i press save button so it can't save record
from this code i get all field access in "subject_enroll/subject_enroll_detail.html" like {{ object.student_name }}
{{ object.enroll_status }}
so it gives value of that field but now i want to edit record in subject_enroll_detail.html template like s
subject_enroll values "draft" to "submit" with click on some buttons in subject_enroll_detail.html template
i tried with form view and updateview but can't find solution
pls help!!!
Thanks in advance!!
from django.views.generic import UpdateView
class StudentRegistrationUpdateView(UpdateView):
model = StudentRegistration
form_class = Subject_EnrollForm #don't need if you are editing all the fields
template_name = 'subject_enroll/add_subject_enroll.html'
https://docs.djangoproject.com/en/1.7/ref/class-based-views/generic-editing/#updateview
in your urls.py
import StudentRegistrationUpdateView
in urls.py don't forget to include 'pk' like below, this determines which object to be updated
url(r'student/(?P<pk>\d+)/update/$', StudentRegistrationUpdateView.as_view(), name='student_registration_update'),

IntegrityError with a foreignKey

i have these models, states and cities,
class State(models.Model):
name = models.CharField(max_length=255)
shortname = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class City(models.Model):
name = models.CharField(max_length=255)
state = models.ForeignKey(State)
def __unicode__(self):
return self.name
and im getting a "IntegrityError (1048, "Column 'state_id' cannot be null")" when i save the form, the weird thing is that the state are created, this is what im doing
def form_valid(self, form):
city = form.cleaned_data['city_name']
state = form.cleaned_data['state_name']
m = State.objects.get_or_create(name=state)
state_id = m[0].id
City.objects.get_or_create(name=state, id=state_id)
form.save()
what can i do?
class StoreForm(ModelForm):
class Meta:
model = Store
fields = '__all__'
class StoreGoogleMapForm(StoreForm):
city_name = forms.CharField(
widget=forms.TextInput(
attrs={'readonly': 'readonly'}
)
)
state_name = forms.CharField(
widget=forms.TextInput(
attrs={'readonly': 'readonly'}
)
)
class Meta(StoreForm.Meta):
exclude = (
'state', 'city'
)
widgets = {
'retailer': forms.HiddenInput(),
'lon': forms.HiddenInput(),
'lat': forms.HiddenInput(),
}
def clean(self):
cleaned_data = super(StoreGoogleMapForm, self).clean()
city_name = cleaned_data.get("city_name")
state_name = cleaned_data.get("state_name")
return cleaned_data
class NewStore(LoginRequiredMixin, CreateView):
model = Store
template_name = "new_store.html"
form_class = StoreGoogleMapForm
def get_context_data(self, **kwargs):
ctx = super(NewStore, self).get_context_data(**kwargs)
ctx['cobrand'] = self.retailer
return ctx
def get(self, request, *args, **kwargs):
self.retailer = get_object_or_404(Cobrand, pk=kwargs['pk'])
self.object = Store(retailer=self.retailer)
form_class = self.get_form_class()
form = self.get_form(form_class)
return self.render_to_response(self.get_context_data(form=form))
def form_valid(self, form):
city = form.cleaned_data['city_name']
state = form.cleaned_data['state_name']
m = State.objects.get_or_create(name=state)
City.objects.get_or_create(name=city, state=m[0])
form.save()
messages.add_message(
self.request,
messages.SUCCESS,
'The store was successfuly created!',
extra_tags='success'
)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse_lazy('store_list', kwargs={'pk': self.kwargs['pk']})
def post(self, request, *args, **kwargs):
self.retailer = get_object_or_404(Cobrand, pk=kwargs['pk'])
self.object = Store(retailer=self.retailer)
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
fix the line as
City.objects.get_or_create(name=city, state=m[0])
you don't need form.save().
Anyway this code is a bit strange, what about your Form?
get_or_create returns two parameters https://docs.djangoproject.com/en/1.7/ref/models/querysets/#django.db.models.query.QuerySet.get_or_create and you can then pass the object straight into the next statement.
state, created = State.objects.get_or_create(name=state)
City.objects.get_or_create(name=state, state=state)
suspect you shouldn't be doing this in form_valid but without rest of your code, can't be sure.

Django form and formset - check if any has users and raise error if not

I have an application which has a form in which you can specify users by name or by formset where you select groups of users or both.
I need to add some sort of validation where the form won't proceed when sum of users selected manually and/or from groups will equal 0.
How do I make a communication between form and formset to raise validation error?
Is there another way of raising an error like in typical form and formset?
def form_valid(self, form):
context = self.get_context_data()
formset = context.get('formset')
is_valid = form.is_valid()
if formset:
is_valid &= formset.is_valid()
if not is_valid:
context['form'] = form
return self.render_to_response(context)
task = form.save()
if self.has_formset():
added_groups_list = []
for formset_form in formset:
...do something...
class TaskForm(forms.ModelForm):
sms_preview = forms.CharField(
label=u"Treść wiadomości SMS", required=False, widget=forms.Textarea(attrs={
'cols': 2,
'rows': 2,
'readonly': 'readonly',
})
)
users = forms.ModelMultipleChoiceField(User.objects.none(), label=u'Użytkownicy', required=False)
class Meta:
model = Task
fields = ('procedure', 'priority', 'location', 'message', 'date_from', 'date_to',
'users')
widgets = {
'date_from': DateTimePickerInput,
'date_to': DateTimePickerInput,
'procedure': forms.Select(attrs={'class': 'chosen',
"data-placeholder": u"Wybierz procedurę",
}),
'message': forms.Textarea(attrs={'cols': 2, 'rows': 2,
'placeholder': u"Własna treść wiadomości (opcjonalnie)"
}),
'hours': forms.TextInput(attrs={'placeholder': u'Godziny'}),
'minutes': forms.TextInput(attrs={'placeholder': u'Minuty'}),
}
def __init__(self, *args, **kwargs):
self.site = kwargs.pop('site')
self.procedure = kwargs.pop('procedure', None)
self.user = kwargs.pop('user', None)
super(TaskForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
layout = Layout('procedure')
date_from = timezone.now() + timezone.timedelta(hours=1)
self.fields['date_from'].initial = date_from.strftime("%d.%m.%Y %H:%M")
date_to = date_from + timezone.timedelta(hours=1)
self.fields['date_to'].initial = date_to.strftime("%d.%m.%Y %H:%M")
self.fields['date_from'].required = True
self.fields['date_to'].required = True
self.fields['message'].label = ""
self.fields['users'].widget.attrs = {
'class': 'chosen',
'data-placeholder': u'Nie wybrano użytkowników.',
'readonly': 'readonly',
'disabled': 'disabled',
}
class TaskActionGroupFormset(forms.formsets.BaseFormSet):
def __init__(self, *args, **kwargs):
self.site = kwargs.pop('site')
self.procedure = kwargs.pop('procedure', None)
super(TaskActionGroupFormset, self).__init__(*args, **kwargs)
#cached_property
def forms(self):
return [self._construct_form(i, site=self.site, procedure=self.procedure)
for i in xrange(self.total_form_count())]
#property
def empty_form(self):
form = self.form(
auto_id=self.auto_id,
prefix=self.add_prefix('__prefix__'),
empty_permitted=True,
site=self.site,
)
self.add_fields(form, None)
return form
Since you are using Django forms, you'll want to use the clean() method and override it to run your validation.