how to save custom ModelForm fields in django - django

i have custom fields in ModelForm and there is no any values on save. im just confuse what to use in view.py to save with data
form.py
class AddCityForm(forms.ModelForm):
duration = forms.ChoiceField(widget=forms.RadioSelect(attrs={
'style': 'background-color: #FAF9F9', 'class': 'mb-3, form-check-inline'}), choices=DURATION_CHOICES)
country = forms.ChoiceField(widget=forms.RadioSelect(attrs={
'style': 'background-color: #FAF9F9', 'class': 'mb-3, form-check-inline'}), choices=CITY_CHOICE)
something = forms.CharField(widget=forms.TextInput(attrs={
'style': 'background-color: #FAF9F9', 'class': 'mb-3'}))
class Meta:
model = Cities
exclude = ['city', 'duration', 'something']
view.py
def add_city(request):
data = dict()
if request.method == 'POST':
form = AddCityForm(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.city = request.POST.get('country')
form.duration = request.POST.get('dur')
form.something = request.POST.get('something')
form = form.save()
messages.success(request, f'Test for Added Successfully')
data['form_is_valid'] = True
else:
data['form_is_valid'] = False
else:
form = AddCityForm()
context = dict(form=form)
data['html_form'] = render_to_string('cites/modal_1.html', context, request=request)
return JsonResponse(data)
can any one help with this ?

Looks like the code is working, i have no idea why did not before i asked this question but i will keep this if any one look for similar question

Related

Django - How to make a current object "ImageField attribute" as the pre-defined value in a Update_Object view?

I'm creating an update view using django-form for updating one of my objects that have the following fields:
class Object(models.Model):
name = models.CharField(max_length=40)
logo = models.ImageField(upload_to='object_logo/')
text_1 = models.TextField()
text_2 = models.TextField()
So, i have created the following form in forms.py:
class ObjectForm(forms.ModelForm):
class Meta:
model = Object
fields = [
'name',
'logo',
'text_1',
'text_2',
]
labels = {
'name': 'Name',
'logo': 'Logo',
'text_1': 'Text 1',
'text_2': 'Text 2',
}
and defined the following view called update_object:
def update_object(request, value):
object = get_object_or_404(Object, pk=value)
if request.method == "POST":
form = ObjectForm(request.POST, request.FILES)
if form.is_valid():
object.name = form.cleaned_data['name']
object.logo = form.cleaned_data['logo']
object.text_1 = form.cleaned_data['text_1']
object.text_2 = form.cleaned_data['text_2']
object.save()
return HttpResponseRedirect(reverse('myApp:detail_object', args=(value, )))
else:
form = ObjectForm(
initial={
'name': object.name,
'logo': object.logo,
'text_1': object.text_1,
'text_2': object.text_2,
}
)
context = {'object': object, 'form': form}
return render(request, 'myApp/update_object.html', context)
My problem is: even with an "initial" value stetted up for logo, i have to select an image every time i will update my object (otherwise i receive the update_object page with the message "This field is required").
Is there a way to make the current object.logo as the pre-defined value of the input in my ObjectForm in the update_object view?
I've already tried to set blank = True in the logo model field (which was a bad idea). I also thought in make an alternative conditional code for form.is_valid() but i dont know how to do it.
Update your forms.py like so:
class ObjectForm(forms.ModelForm):
class Meta:
model = Object
fields = '__all__'
...and views.py:
def update_object(request, value):
object = get_object_or_404(Object, pk=value)
if request.method == "POST":
form = ObjectForm(request.POST, request.FILES, instance=object)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('myApp:detail_object', args=(value, )))
else:
form = ObjectForm(instance=object)
context = {'object': object, 'form': form}
return render(request, 'myApp/update_object.html', context)
It can be done like this (more clean)
In case share your template code

django formset displaying wrong objects

when creating a new recipe post, I use two formsets for ingredients and directions. however, the new post formsets are being populated by existing ingredient and direction objects when they should be empty. here is my view for the new post and the forms:
def post_new(request):
form = PostForm()
ingredient_form = IngredientFormSet(prefix='ingredient_form')
direction_form = DirectionFormSet(prefix='ingredient_form')
if request.method == "POST":
form = PostForm(request.POST, request.FILES)
ingredient_form = IngredientFormSet(request.POST, prefix='ingredient_form')
direction_form = DirectionFormSet(request.POST, prefix='direction_form')
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
if ingredient_form.is_valid():
for i_form in ingredient_form:
if i_form.is_valid() and i_form.has_changed():
i_form.instance.recipe = post
i_form.save()
if direction_form.is_valid():
for d_form in direction_form:
if d_form.is_valid() and d_form.has_changed():
d_form.instance.recipe = post
d_form.save()
return redirect('post_detail', pk=post.pk)
return render(request, 'blog/post_edit.html', {'form': form, 'ingredient_form': ingredient_form, 'direction_form': direction_form})
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'image', 'text', 'prep_time', 'cook_time', 'servings_first', 'servings_second', 'tags']
IngredientFormSet = modelformset_factory(Ingredient, fields=['name',
'int_amount',
'float_amount',
'measurement'
], extra=15)
DirectionFormSet = modelformset_factory(Direction, fields=['text',
'order'
], extra=25)
Not sure why it is needed, but setting each formsets query to "None" solved the problem:
def post_new(request):
form = PostForm()
ingredient_form = IngredientFormSet(queryset=Ingredient.objects.none(), prefix='ingredient_form')
direction_form = DirectionFormSet(queryset=Direction.objects.none(), prefix='ingredient_form')

POST request not working for Django form and Django formset

I have a form, ApplyJobForm and a Formset, ApplyJobFormset. GET method works when I pass the form and the formset to a view, but for the post request the form and the formset is_valid() isn't working, after clicking submit it returns me to a view without saving. I am unable to save the form with the formset, I don't know what I'm doing wrong here.
Here are my codes.
models.py
class Applicants(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name='applicants')
experience = models.IntegerField(blank=True, null=True)
cv = models.FileField(upload_to=user_directory_path)
degree = models.CharField(choices=DEGREE_TYPE, blank=True, max_length=10)
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return f'{self.user.get_full_name()} Applied'
class Certification(models.Model):
applicant = models.ForeignKey(Applicants, on_delete=models.CASCADE, related_name='applicant_certifications')
name = models.CharField(max_length=50)
certification = models.FileField(upload_to=user_directory_path, blank=True)
def __str__(self):
return f'{self.user.get_full_name()} certificate'
forms.py
class ApplyJobForm(forms.ModelForm):
class Meta:
model = Applicants
fields = ('job', 'degree', 'experience', 'cv')
exclude = ('job',)
labels = {
'degree': 'Degree',
'experience': 'Experience',
'cv': 'CV',
}
widgets = {
'degree': forms.Select(attrs={
'class': 'form-control',
}
),
'experience': forms.NumberInput(
attrs={
'class': 'form-control',
}
),
'cv': forms.FileInput(
attrs={
'class': 'form-control',
}
),
}
ApplyFormset = modelformset_factory(
Certification,
fields=('name', 'certification'),
extra=1,
widgets={
'name': forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'Certification name'
}
),
'certification': forms.FileInput(
attrs={
'class': 'form-control',
'placeholder': 'Upload certification'
}
)
}
)
views.py
def job_apply(request, job_id=None):
template_name = 'apply_form.html'
applyform = ApplyJobForm(request.GET or None)
job = get_object_or_404(Job, id=job_id)
formset = ApplyFormset(queryset=Certification.objects.none())
if request.method == 'GET':
context = {'applyform': applyform, 'formset': formset}
return render(request, template_name, context)
elif request.method == 'POST':
applyform = ApplyJobForm(request.POST)
formset = ApplyFormset(request.POST)
if applyform.is_valid() and formset.is_valid():
apply = applyform.save(commit=False)
applyform.job = job
apply.save()
for form in formset:
# so that `apply` instance can be attached.
certification = form.save(commit=False)
certification.apply = apply
certification.save()
return redirect('successful-apply')
else:
return redirect('job-detail', id=job.id)
return render(request, template_name, {'applyform': applyform, 'formset': formset})
Here an applicant can add as many certification field when applying for a job, although the certification field is not a required field. Certification model is bound to the Applicants model.
.html
<form class="form" method="POST" action="" enctype="multipart/form-data" role="form" autocomplete="off">
.................
</form>
First of all, never redirect if your forms are not valid. You want to render your template with the invalid form so that you can display the errors to the user. This also helps debugging since you'll see the errors.
So in your view, remove these two lines:
else:
return redirect('job-detail', id=job.id)
so that the invalid case renders the forms in your template.
Next, since you have files to upload, you need to initialise forms that require files with request.FILES:
formset = ApplyFormset(request.POST, request.FILES)
(and the same for applyform).
Finally make sure that in your template you are also displaying all the errors, either on each field ({{ form.<field>.errors }}) or globally ({{ form.errors }}).

How to save Foreign Key text input in Django model form

My view passes an id to my form. This id is a foreign key from another table. I am not able to save the id in the database table.
(id : voucher_id, table in which i am saving the form : TmpPlInvoicedet)
What i want to do
Send voucher_id from (View) to ---> TmpFormDetForm (Form) ---> TmpPlInvoicedet (DB)
Trying to get instance from the table 'TmpPlInvoice' (which has voucher_id as PK) and save it in the form gives me
DoesNotExist at /new/ TmpPlInvoice matching query does not exist
What am i doing wrong?
Views.py
def new_invoic(request):
# Create a voucher id according to my criteria
temp_vid = TmpPlInvoice.objects.order_by().values_list("voucher_id", flat=True).distinct()
if not temp_vid:
voucher_id = str(1).zfill(4)
else:
voucher_id = str(int(max(temp_vid)) + 1).zfill(4)
# POST METHOD TRying to show the voucher_id in the form in readonly format
if request.method == 'POST':
form_pk = TmpForm(request.POST or None, voucher_id=voucher_id,initial={'voucher_id': voucher_id})
if form.is_valid():
form_pk.save()
form = TmpFormDetForm(request.POST or None, voucher=voucher_id, initial={'voucher': voucher_id})
# My assumption is that since i have save the voucher_id in the TmpInvoice table so i can get the PK voucher_id value and save it in the TmpInvoiceDetForm
form.save()
return HttpResponseRedirect('/new/')
else:
return render_to_response('test.html',{'form': form, 'form_pk': form_pk},context_instance=RequestContext(request))
else:
form_pk = TmpForm(voucher_id=voucher_id,initial={'voucher_id': voucher_id})
form = TmpFormDetForm(voucher=voucher_id, initial={'voucher': voucher_id})
return render_to_response('test.html',{'form': form, 'form_pk': form_pk},context_instance=RequestContext(request))
Forms.py
# This form contains the FK. This one is giving errors while saving.
class TmpFormDetForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
voucher = kwargs.pop('voucher', None)
super(TmpFormDetForm, self).__init__(*args, **kwargs)
self.fields['voucher'].initial = TmpPlInvoice.objects.get(voucher_id=voucher)
voucher = forms.CharField(widget=forms.TextInput(attrs={'size':'40'}))
class Meta:
model = TmpPlInvoicedet
exclude = ['emp_id','particulars','qty', 'rate' , 'itemtot', 'stock_code' ]
widgets = {
'voucher': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '', 'required': 'False', 'name': 'voucher','readonly': 'readonly'}),
'lineitem': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Add Total', 'required': 'False', 'blank': 'True'})}
# This form takes the PK. I save the PK here first.
class TmpForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
voucher_id = kwargs.pop('voucher_id', None)
super(TmpFor, self).__init__(*args, **kwargs)
self.fields['voucher_id'].initial = voucher_id
pos_code = MyModelChoiceField(queryset=Positions.objects.all(), widget=forms.Select(attrs={'class': 'select2_single form-control', 'blank': 'True'}))
cust = MyModelChoiceField(queryset=Custodian.objects.all(), to_field_name='acct_id',widget=forms.Select(attrs={'class': 'select2_single form-control', 'blank': 'True'}))
acct = MyModelChoiceField(queryset=Item.objects.all(), to_field_name='stock_code',widget=forms.Select(attrs={'class':'select2_single form-control', 'blank': 'True'}))
voucher_date = forms.DateField(widget=forms.TextInput(attrs={'tabindex': '-1', 'class': 'form-control has-feedback-left', 'id': 'single_cal1','aria-describedby': 'inputSuccess2Status'}))
class Meta:
model = TmpPlInvoice
exclude = ['net_amt', 'post_date', 'address', 'posted']
widgets = {
'voucher_id': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '', 'required':'False', 'name': 'voucher_id', 'readonly': 'readonly'}),
'voucher_date': forms.TextInput(attrs={'tabindex': '-1', 'class': 'form-control has-feedback-left', 'id': 'single_cal1','aria-describedby': 'inputSuccess2Status'}),
'particulars': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Add Particulars', 'required':'False'}),
}
Models.py
class TmpPlInvoicedet(models.Model):
stock_code = models.CharField(max_length=13, blank=True, null=True)
voucher = models.ForeignKey(TmpPlInvoice, db_column='voucher_id')
lineitem = models.CharField(max_length=6)
particulars = models.CharField(max_length=200, blank=True, null=True)
qty = models.FloatField(blank=True, null=True)
rate = models.FloatField(blank=True, null=True)
itemtot = models.FloatField(blank=True, null=True)
emp_id = models.CharField(max_length=8, blank=True, null=True)
class Meta:
managed = False
db_table = 'tmp_pl_invoicedet'
unique_together = (('voucher', 'lineitem'),)
Easy peesy.
def master_detail(request):
def get_new_voucher_id():
temp_vid = TmpPlInvoice.objects.order_by().values_list("voucher_id", flat=True).distinct()
logger.info('Voucher ID already present %s', temp_vid)
if not temp_vid:
voucher_id = str(1).zfill(4)
else:
voucher_id = str(int(max(temp_vid)) + 1).zfill(4)
return voucher_id
voucher_id = get_new_voucher_id()
author_form = TmpForm(initial={'voucher_id': voucher_id})
author = TmpPlInvoice()
BookFormSet = inlineformset_factory(TmpPlInvoice, TmpPlInvoicedet, exclude=('emp_id', 'itemtot', 'voucher', 'lineitem','id'),
form=TmpFormDetForm, extra=1)
formset = BookFormSet(instance=author)
if request.method == 'POST':
logger.info('*'*50)
author = TmpForm(request.POST, initial={'voucher_id': voucher_id})
if author.is_valid():
logger.info('Data for Author is %s', author.cleaned_data)
created_author = author.save()
formset = BookFormSet(request.POST, instance=created_author)
if formset.is_valid():
logger.info('Data for Book is %s', formset.cleaned_data)
formset.save()
else:
logger.info('Formset errors %s', formset.errors)
else:
logger.info('Master form errors %s', author.errors)
logger.info('*'*50)
return HttpResponseRedirect('/new/')
else:
logger.info('Formset from GET is %s', formset.errors)
return render_to_response('new_invoice.html',
{'form': author_form, 'formset': formset},context_instance=RequestContext(request))
You seem to be creating a new invoice ID and then, in your form, attempting to get the invoice matching that ID. But that invoice doesn't exist yet, of course, because you haven't created it.
You might want to use get_or_create to ensure that the invoice is created if it doesn't exist.

django formset initial data showing id (primary key)

For some reason, the exclude in my forms isn't working and the primary key of my Item models is showing up on my formset. How can I get rid of it?
Form:
class ItemForm(forms.ModelForm):
class Meta:
model = Item
fields = ('name',
'description',
'quantity',
'start',
'end',
'cost_price',
'selling_price',)
widgets = {
'cost_price': forms.TextInput(attrs={'onChange':'updateSellingPrice()'}),
'description': forms.Textarea,
'start': SelectDateWidget,
'end': SelectDateWidget}
exclude = ('id')
ItemFormSet = modelformset_factory(Item, form=ItemForm, max_num=5, extra=3, exclude=('id'))
View:
def item_details(request, event_slug, role_id, module_slug):
event = get_object_or_404(Event, slug=event_slug)
payment_details = EventPaymentDetail.objects.get_or_create(event=event)[0]
try:
item_details = Item.objects.filter(event=event)
except:
item_details = Item.objects.get_or_create(event=event)[0]
if request.method == 'POST':
item_formset = ItemFormSet(request.POST)
#display_error(request, item_formset)
if item_formset.is_valid():
instances = item_formset.save(commit=False)
for instance in instances:
instance.event = event
instance.save()
messages.success(request, 'Item details successfully saved!')
url = reverse('event_admin_dashboard', args=[event_slug, role_id])
return redirect(url)
else:
item_formset = ItemFormSet()
currency_type = payment_details.currency
template = 'registration/item_details.html'
return render(request, template, locals())
I don't believe it is possible to exclude the id field. I'm afraid I can't give you an explanation or a link to the docs.
Aside:
It's not the issue here, but you're missing a comma on your exclude tuple. That's not the problem here, but it means that django interprets it as
exclude = ('i', 'd')
It should be:
exclude = ('id',)