Hiding foreign key fields from ModelForms in Django - django

I am using django ModelForms to generate my input forms.
I specify in my form model to only use a set of fields:
class <Model>Form(ModelForm):
class Meta:
model = <Model>
fields = ('date', 'comment_1')
My model is defined as:
class <Model>(models.Model):
fk_id_1 = models.ForeignKey(<ExternalModel1>, null=False, blank=False)
fk_id_2 = models.ForeignKey(<ExternalModel2>, null=False, blank=False)
date = models.DateField()
comment_1 = models.CharField(max_length=100)
comment_2 = models.CharField(max_length=100)
However, the ForeignKey boxes show.
How is it possible for me to hide them from the form? Also, how can I set the values for those dropboxes from within the view and not sure, say JQuery externally to do it? Ideally, after the ''is_valid()'' check, I would like to set the IDs of my Foreign Keys and then do save. Maybe I should look into solving this using another way?
This is the View:
def <Model>_add(request, trainee_id):
<Model>FormSet = modelformset_factory(<Model>)
if request.method == 'POST':
formset = <Model>FormSet(request.POST, request.FILES)
if formset.is_valid() and formset.has_changed():
formset.save()
# do something.
else:
formset = <Model>FormSet(queryset=<Model>.objects.none())
return render_to_response("<Model>_add.html", {
"formset": formset, "fk_id_1": fk_id_1,
}, context_instance=RequestContext(request))
I can solve this issue using JQuery but I would like a more elegant approach.
Note: I tried posting this earlier but I think it was not as clear as it is here: Presetting values on a foreign entity relationship in a ModelForm ... I didn't understand exactly what was said about QuerySet.

You need to be a bit more explicit in how you define the form:
class <Model>Form(ModelForm):
class Meta:
model = <Model>
fields = ['date', 'comment_1']
exclude = ['fk_id_1', 'fk_id_2']
Then in your view:
from django.shortcuts import render, redirect
def <Model>_add(request, trainee_id):
<Model>FormSet = modelformset_factory(<Model>)
if request.method == 'POST':
formset = <Model>FormSet(request.POST, request.FILES)
if formset.is_valid() and formset.has_changed():
forms = formset.save(commit=False)
for form in forms:
form.fk_id_1 = SomeOtherModel.objects.get(pk=1)
form.fk_id_2 = SomeOtherModel.objects.get(pk=2)
form.save()
# add your success redirect here, for example:
return redirect('/')
else:
formset = <Model>FormSet(queryset=<Model>.objects.none())
return render(request, "<Model>_add.html", {"formset": formset})

Every ModelForm also has a save() method. doc
or:
in views.py
form.instance.fk_id_1 = ...
form.instance.fk_id_2 = ...
form.save()

Related

set slug field form manually in views Django

I'm new in Django and I'm trying to pre fill one of the fields of my form with a slug.
I'm getting the slug from another model. I'm not using ForeignKey because that shows me a list with my objects and I want to save in the form the same slug that I'm using in the url.
Maybe I'm not thinking this right. What should I do?
Thank you!
This are my models:
from django.db import models
class Thing(models.Model):
name = models.CharField(max_length=255,)
rut = models.CharField(max_length=12, blank= True)
cel = models.CharField(max_length=12, blank= True)
slug = models.SlugField(unique=True)
class Control(models.Model):
id_p = models.SlugField()
pa = models.CharField(max_length=3,)
My forms
from django.forms import ModelForm
from collection.models import Thing, Control, Medicamento
class ThingForm(ModelForm):
class Meta:
model = Thing
fields = ('name', 'rut','cel','pet',)
class ControlForm(ModelForm):
class Meta:
model = Control
exclude = ['id_p']
This is what I'm doing in the views
def add_control(request, slug):
thing = Thing.objects.get(slug=slug)
form_class = ControlForm
form_class(initial={'id_p':thing})
if request.method == 'POST':
form = form_class(request.POST)
if form.is_valid():
form.save()
return redirect('thing_detail', slug=thing.slug)
else: form = form_class()
return render(request, 'things/control.html', {
'thing': thing,
'form': form,
})
So, I figure it out!
In views.py, after " if form.is_valid():"
I put this:
prev = form.save(commit=False)
prev.id_p = thing.slug
prev.save()
In that way I put the data in the excluded field before I commit the form.

What's the best way to include a ModelForm from a different Model in a Template?

I have the following models:
class Picture(models.Model):
title = models.CharField(max_length=255)
(etc)
And
class Report(models.Model):
complaint = models.TextField()
picture = models.ForeignKey('Picture')
What i'd like to be able to do is
a) Include the report ModelForm in the 'Picture' ModelView template
b) Prepopulate the picture field in the report Modelform with the relevant picture
I've been messing around with contextprocessors, inclusiontags and trying to pass the variable through a querystring to a new page, but they all seem quite complex and to not work correctly.
What I'd like help with is understanding the most 'django' way to do this, and any pointers to getting this done.
Solution
With Scott's help, the working solution is:
views.py
def picture(request, slug):
picture = Picture.objects.get(slug=str(slug))
d = dict(picture=picture, form=ReportPicture())
d.update(csrf(request))
if request.method == 'POST':
form = ReportPicture(request.POST)
if form.is_valid():
report = form.save(commit=False)
report.picture = picture
report.save()
return redirect(picture.get_absolute_url())
return render_to_response("picture_detail.html", d)
I believe you are wanting inline formsets (docs).
# models.py
class Picture(models.Model):
title = models.CharField(max_length=255)
class Report(models.Model):
complaint = models.TextField()
picture = models.ForeignKey('Picture')
# views.py
from django.forms.models import inlineformset_factory
from .models import Picture, Report
def manage_picture(request, pk):
picture = Picture.objects.get(pk=pk)
ReportInlineFormSet = inlineformset_factory(Picture, Report)
if request.method == "POST":
formset = ReportInlineFormSet(request.POST, request.FILES, instance=picture)
if formset.is_valid():
formset.save()
return HttpResponseRedirect(picture.get_absolute_url())
else:
formset = ReportInlineFormSet(instance=picture)
return render_to_response("manage_picture.html", {"formset": formset})
If you're using Class Based Views Django doesn't natively offer any inline formset support but there is an excellent app that handles most of this for you called django-extra_views.

Dynamic Forms with Foreign Keys in Django

I have the following models
class Make(models.Model):
make_name = models.CharField(max_length=32)
def __unicode__(self):
return self.book_title
class MakeModel(models.Model):
model_number = models.IntegerField()
model_capacity = models.IntegerField()
model_capacity_unit = models.CharField(max_length=4)
Make = models.ForeignKey(Make)
def __unicode__(self):
return self.model_number
Basically, I want my form to have all the Make details at the top, and all the MakeModel details in a grid below, and to be able to add more MakeModels with ease. Such as in this mockup
https://www.dropbox.com/s/e7rg3zxe6y8q9fi/invoicedetails.gif
Any ideas what needs doing? People mention things like inlineformset_factory, but I'm not convinced either how to use it, or if it will do the thing I expect.
Any help would be appreciated
You need a form and a formset.
A form: one form
A formset: multiple copies of one form
Your view would look something like this in the POST cycle:
Update: oh right, foreignkey. The easiest way to be honest is just to commit=False the formset and manually assign the FK. You can use an inlineformset as well. https://docs.djangoproject.com/en/dev/ref/forms/models/#django.forms.models.inlineformset_factory
FormSet = modelformset_factory(MakeModel)
Form = modelform_factory(Make)
def myview(request):
formset = FormSet(request.POST or None)
form = Form(request.POST or None)
if request.method == 'POST':
if formset.is_valid() and form.is_valid():
main_instance = form.save()
formset.save(commit=False)
for instance in formset:
instance.fk = main_instance
instance.save()
https://docs.djangoproject.com/en/dev/topics/forms/formsets/

Saving Django ModelForm with a ForeignKey

This is probably a fairly simple question, but I can't seem to figure it out from the Django Docs. I'm trying to save a two ModelForms at once with one being a ForeignKey of another. I'm not sure how to write the logic in the views to ensure these go together properly.
models.py
class Address(models.Model):
address = models.CharField(max_length=100)
city = models.CharField(max_length=50)
zipcode = models.PositiveIntegerField()
class Store(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=140, blank=True)
address = models.ForeignKey(Address, null=True)
forms.py
class CreateStore1Form(forms.ModelForm):
class Meta:
model = Store
exclude = ('address',)
class CreateStore2Form(forms.ModelForm):
class Meta:
model = Address
views.py
#login_required
def create(request):
if request.method == "POST":
form1 = CreateStore1Form(request.POST)
form2 = CreateStore2Form(request.POST)
if form1.is_valid() and form2.is_valid():
store = form1.save(address)
new_address = form2.save(commit=False)
new_address.store = store
mew_address.save()
else:
form1 = CreateStore1Form()
form2 = CreateStore2Form()
return render(request, 'create.html', locals())
Any help would be appreciated. Thanks!
Django provides inline formsets for this use case:
Inline formsets is a small abstraction layer on top of model formsets.
These simplify the case of working with related objects via a foreign
key.
forms.py
class AddressForm(forms.ModelForm):
class Meta:
model = Address
class StoreForm(forms.ModelForm):
class Meta:
model = Store
exclude = ('address',)
views.py
from django.forms.models import inlineformset_factory
#login_required
def create(request):
AddressInlineFormSet = inlineformset_factory(Address, Store, form=AddressForm)
if request.method == 'POST':
storeForm = StoreForm(request.POST)
if storeForm.is_valid():
new_store = storeForm.save()
addressInlineFormSet = AddressInlineFormSet(request.POST, request.FILES, instance=new_store)
if addressInlineFormSet.is_valid():
addressInlineFormSet.save()
return HttpResponseRedirect(reverse('some_happy_customer_url'))
else:
classificationformset = ClassificationInlineFormSet(request.POST, request.FILES, instance=new_store)
else:
addressInlineFormSet = AddressInlineFormSet()
storeForm = StoreForm()
return render(request, 'create.html', locals())
Please see also this question for more details.

Django ModelForms: Trying to save a form with a foreign key

Django will just go to the else condition.
here's the code:
models.py
class StakeholderProfile(models.Model):
types = models.ForeignKey(Stakeholder)
name = models.CharField(blank=False, max_length=50)
forms.py
class SPForm(forms.ModelForm):
class Meta:
model = StakeholderProfile
exclude = ('key_contact_person',)
views.py
def profile(request):
stakeholderprofile = StakeholderProfile.objects.all()
if request.method == 'POST':
form = SPForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/profile/')
else:
form = SPForm()
return render_to_response('profile.html',{'form':form,'sp':stakeholderprofile})
I really need your help sir/maam.
You are excluding a field that doesn't exist in StakeHolderProfile.
Also be sure you added method='POST' in your form tag.