Django inline formset: The inline foreign key did not match the parent instance primary key - django

There seem to be a lot of questions out there on this topic, but I haven't been able to find anything that has solved this problem for me. I am trying to make a view to create Recipe object, which has foreign key sets for Ingredients and Instructions. When I try to submit, the formsets give me the error 'recipe': [u'The inline foreign key did not match the parent instance primary key.']. Here's my complete view:
def recipe_add(request):
profile = profile_from_request(request)
if request.method == 'POST':
recipe_form = RecipeForm(request.POST)
if recipe_form.is_valid():
recipe = recipe_form.save(commit=False)
recipe.user = profile_from_request(request)
ingredient_form = IngredientFormSet(request.POST, prefix='ingredient', instance=recipe)
instruction_form = InstructionFormSet(request.POST, prefix='instruction', instance=recipe)
if ingredient_form.is_valid() and instruction_form.is_valid():
recipe = recipe.save()
ingredient_form.save()
instruction_form.save()
messages.success(request, _("Recipe added."))
return HttpResponseRedirect(reverse("recipes:recipe_list"))
else: # GET
recipe_form = RecipeForm()
ingredient_form = IngredientFormSet(prefix='ingredient', instance=Recipe())
instruction_form = InstructionFormSet(prefix='instruction', instance=Recipe())
return render(
request, 'recipes/recipe_add.html',
{
'profile': profile,
'recipe_form': recipe_form,
'ingredient_form': ingredient_form,
'instruction_form': instruction_form,
}
)
I'm not sure if the issue comes from creating the formsets in the GET or POST methods. I've tried messing with the instance argument in both but haven't gotten anything to work.

I had a similar issue because I forgot to add the management form for my formset in my template.
In your templates, you must have something like this :
{{ ingredient.management_form }}
{{ instruction.management_form }}
Quick way to verify is to inspect your form code in your browser and look for the hidden fields that this management form is rendering into.
You can then see if the foreign key value of those formsets matches the recipe primary key which may point you in the right direction.

Related

(Hidden field id) Select a valid choice. That choice is not one of the available choices. (Django)

I'm receiving this error when I try to submit two formsets. After I fill the form and click the save button, it gives the error:
(Hidden field id) Select a valid choice. That choice is not one of the available choices.
I'm trying to create dynamic form so that the user can add new sections and also new lectures inside the section when they click "Add" button. The adding new form function works well, I just have problem saving it to the database.
Views.py
def addMaterials(request, pk):
course = Course.objects.get(id=pk)
sections = CourseSection.objects.filter(course_id=pk)
materials = CourseMaterial.objects.filter(section__in=sections)
SectionFormSet = modelformset_factory(CourseSection, form=SectionForm, extra=0)
sectionformset = SectionFormSet(request.POST or None, queryset=sections)
MaterialFormSet = modelformset_factory(CourseMaterial, form=MaterialForm, extra=0)
materialformset = MaterialFormSet(request.POST or None, queryset=materials)
context = {
'course': course,
'sectionformset': sectionformset,
'materialformset': materialformset,
}
if request.method == "POST":
if all([sectionformset.is_valid() and materialformset.is_valid()]):
for sectionform in sectionformset:
section = sectionform.save(commit=False)
section.course_id = course.id
section.save()
for materialform in materialformset:
material = materialform.save(commit=False)
print(material)
material.section_id = section #section.id or section.pk also doesn't work
material.save()
return('success')
return render(request, 'courses/add_materials.html', context)
Forms.py
class SectionForm(forms.ModelForm):
class Meta:
model = CourseSection
fields = ['section_name', ]
exclude = ('course_id', )
class MaterialForm(forms.ModelForm):
class Meta:
model = CourseMaterial
fields = ['lecture_name', 'contents']
The second formset which is materialformset need the section id from the first formset hence why there is two loop in views.
Can someone help me to solve this. I'm not sure how to fix it.
This is the what I'm trying to do.
I'm new to django but I had to face with the same problem. My solution was to handle singularly each formset inside 'views.py'.
In the template.html, create a tag for each formset you have, than inside that tag put <input type="submit" name="form1">(Note that name is important and must be different with the respect of the form you are submitting).
Then in views.py, instead for writing if all([sectionformset.is_valid() and materialformset.is_valid()]), try like this:
if 'form1' in request.POST:
if sectionformset.is_valid():
sectionformset.save()
# other rows of your code
return('success')
if 'form2' in request.POST:
if materialformset.is_valid():
materialformset.save()
# etc. etc.

How can I called a view within another view django

Currently, I have a view that essentially closes a lead, meaning that it simply copies the information from one table (leads) to another (deals), now what I really would like to do is that after clicking close, the user is redirected to another page where the user can update some entries (sales forecast), I have a view that updates the lead, so I thought that I can do something like below:
#login_required
def close_lead(request):
id = request.GET.get('project_id', '')
keys = Leads.objects.select_related().get(project_id=id)
form_dict = {'project_id': keys.project_id,
'agent': keys.agent,
'client': keys.point_of_contact,
'company': keys.company,
'service': keys.services,
'licenses': keys.expected_licenses,
'country_d': keys.country
}
deal_form = NewDealForm(request.POST or None,initial=form_dict)
if request.method == 'POST':
if deal_form.is_valid():
deal_form.save()
obj = Leads.objects.get(project_id=id)
obj.status = "Closed"
obj.save(update_fields=['status'])
## Changing the Forecast Table Entry
forecast = LeadEntry.objects.filter(lead_id=id)
for i in forecast:
m = i
m.stage = "Deal"
m.save(update_fields=['stage'])
messages.success(request, 'You have successfully updated the status from open to Close')
update_forecast(request,id)
else:
messages.error(request, 'Error updating your Form')
return render(request,
"account/close_lead.html",
{'form': deal_form})
This view provides the formset that I want to update after closing the lead
#login_required
def update_forecast(request,lead_id):
# Gets the lead queryset
lead = get_object_or_404(Leads,pk=lead_id)
#Create an inline formset using Leads the parent model and LeadEntry the child model
FormSet = inlineformset_factory(Leads,LeadEntry,form=LeadUpdateForm,extra=0)
if request.method == "POST":
formset = FormSet(request.POST,instance=lead)
if formset.is_valid():
formset.save()
return redirect('forecast_lead_update',lead_id=lead.project_id)
else:
formset = FormSet(instance=lead)
context = {
'formset':formset
}
return render(request,"account/leadentry_update.html",context)
As you can see I’m calling this function update_forecast(request,id) after validating the data in the form, and I would have expected to be somehow redirected to the HTML page specified on that function, however, after clicking submit, the form from the first view is validated but then nothing happens, so I'm the function doesn't render the HTML page
My question how can I leverage existing functions in my views?, obviously, I will imagine that following the DRY principles you can do that in Django, so what am I doing wrong ?, how can I call an existing function within another function in views?
A view returns a response object. In your current code, you're calling a second view but not doing anything with its response. If you just wanted to display static content (not a form that might lead to an action that cares about the current URL) you could return the response object from the second view - return update_forecast(request, id).
But since your second view is displaying a form, you care about what the action for the view from the second form is. The typical Django idiom is to have forms submit to the current page's URL - that wouldn't work if you just call it and return its response object. You could customize the action in the second view, say adding an optional parameter to the view, but the usual idiom for form processing is to redirect to the view you want to show on success. Just as you do in the update_forecast view. Something like this:
messages.success(request, 'You have successfully updated the status from open to Close')
return redirect('update_forecast', lead_id=id)

Getting an ID from a one-to-many field

I am trying to get a ID for a related Model. I have tried several things but can not figure it out. below is the code I am using.
def assign_load(request):
form = DispatchForm(request.POST or None)
loads = Load.objects.all().filter(active=True, dispatched=False, picked_up=False, delivered=False,
billed=False, paid=False)
context_dict = {'dispatch' : form, 'load' : loads}
if form.is_valid():
save_it = form.save()
save_it.save()
new_dispatch = Dispatch.objects.all().filter(id=save_it.id)
print(new_dispatch.model.load_number.pk)
return HttpResponseRedirect('/dispatch/dispatch/')
return render(request, 'dispatch/dispatch_form.html', context_dict)
new_dispatch is the newly created record that has a one-to-many releation with a model called Loads. I need to get the load_number PK when I try to print just the new_dispatch.model.load_number I get back the following.
<django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x0000029016E34710>
but what I need is the ID for that record so that I can updated some fields.
Thank you very much for your help, I am new to the Django world and trying to figure this stuff out.
Use Dispatch.objects.get(id=save_it.id) instead of Dispatch.objects.all().filter(id=save_it.id)

Can you use a Django form multiple times in one view?

I have a Django view that uses one form multiple times. The form is just a boolean field form that is supposed to initialize to True but then the user can decide to uncheck the boxes or not.
The problem I'm having is that the all of the fields evaluate to True no matter what the user leaves checked. Is this a problem with using the same form multiple times, or did I mess something else up?
The form looks like this:
class DataTypeForm(forms.Form):
def __init__(self,*args,**kwargs):
section_label = kwargs.pop('section_label')
initial_value = kwargs.pop('initial_value')
super(DataTypeForm,self).__init__(*args,**kwargs)
self.fields['dataType'].label=mark_safe(section_label)
self.fields['dataType'].initial=initial_value
self.fields['dataType'].required=False
dataType = forms.BooleanField(required=False)
This is the view:
def Manual_Request(request):
form_dict = {}
arg_dict = {}
message = message = {'last_url':'Nominal_Request'}
if request.method == 'POST':
logger.info("Query submitted, beginning query results render for:")
form_NOM = DataTypeForm(request.POST or None,section_label="ENG_NOM",initial_value=True)
form_DDM = DataTypeForm(request.POST or None,section_label="SCI_DDM",initial_value=True)
form_RAW = DataTypeForm(request.POST or None,section_label="SCI_RAW",initial_value=False)
if form_NOM.is_valid():
NOM = form_NOM.cleaned_data['dataType']
arg_dict.update({'ENG_NOM':str(NOM)})
logger.info("ENG_NOM: {val}".format(val=NOM))
if form_DDM.is_valid():
DDM = form_DDM.cleaned_data['dataType']
arg_dict.update({'SCI_DDM':str(DDM)})
logger.info("SCI_DDM: {val}".format(val=DDM))
if form_RAW.is_valid():
RAW = form_RAW.cleaned_data['dataType']
arg_dict.update({'SCI_RAW':str(RAW)})
logger.info("SCI_RAW: {val}".format(val=RAW))
return Request_Results(request,args_dict)
else:
logger.info("Rendering query page")
form_NOM = DataTypeForm(section_label="ENG_NOM",initial_value=True)
form_DDM = DataTypeForm(section_label="SCI_DDM",initial_value=True)
form_RAW = DataTypeForm(section_label="SCI_RAW",initial_value=True)
form_dict.update({'form_NOM':...etc})
return render(request,'InterfaceApp/COMMRequest_Manual.html',form_dict)
Help much appreciated!
I haven't run your code, but my best guess is that yes, it's a problem with using the same form multiple times in the same view. The reason? All of your <input type="checkbox" name="..." ... /> tags will have the same name, 'dataType'. The user's browser knows nothing of your back-end, and will just send, for example, dataType=on&dataType=on as POST data for the three fields if two are checked and one is not.
Seeing the problem here? How is django supposed to know which of those dataType fields are for your NOM, DDM, or RAW forms? It can't know.
You should be able to solve this using form prefixes. In short, there's a kwarg that you can pass to a form's __init__() that will cause a prefix to be added to all of the form items in the rendered HTML. So, for example:
form_NOM = DataTypeForm(request.POST or None, section_label="ENG_NOM",
initial_value=True, prefix="NOM")
form_DDM = DataTypeForm(request.POST or None, section_label="SCI_DDM",
initial_value=True, prefix="DDM")
form_RAW = DataTypeForm(request.POST or None, section_label="SCI_RAW",
initial_value=False, prefix="RAW")
Hope that helps!
This is exactly what Django formsets are for. They allows you to create a set of the same type of form. It handles prefixes, and adds a management form so that Django doesn't get confused as to what data comes from what form.
https://docs.djangoproject.com/en/1.8/topics/forms/formsets/

Help understanding a Django view

I am trying to follow the code listed on https://github.com/alex/django-ajax-validation/blob/master/ajax_validation/views.py
I have been able to understand a small chunk of it. I have added comments stating my understanding of what is happening.
I would really appreciate some assistance on questions I listed in comments next to the lines I couldn't quite follow.
def validate(request, *args, **kwargs):
# I thing it is some sort of initializations but I cannot really understand what's happening
form_class = kwargs.pop('form_class')
defaults = {
'data': request.POST
}
extra_args_func = kwargs.pop('callback', lambda request, *args, **kwargs: {})
kwargs = extra_args_func(request, *args, **kwargs)
defaults.update(kwargs)
form = form_class(**defaults)
if form.is_valid(): #straightforward, if there is no error then the form is valid
data = {
'valid': True,
}
else:
# if we're dealing with a FormSet then walk over .forms to populate errors and formfields
if isinstance(form, BaseFormSet): #I cannot really understand what is BaseFromSet
errors = {}
formfields = {}
for f in form.forms: # I am guessing that this is for when there are multiple form submitted for validation
for field in f.fields.keys(): # I think he is looping over all fields and checking for error. what does add_prefix () return? and what is formfields[]?
formfields[f.add_prefix(field)] = f[field]
for field, error in f.errors.iteritems():
errors[f.add_prefix(field)] = error
if form.non_form_errors():
errors['__all__'] = form.non_form_errors() # what is the '__all__'?
else:
errors = form.errors
formfields = dict([(fieldname, form[fieldname]) for fieldname in form.fields.keys()])
# if fields have been specified then restrict the error list
if request.POST.getlist('fields'): # I am having a hard time understanding what this if statement does.
fields = request.POST.getlist('fields') + ['__all__']
errors = dict([(key, val) for key, val in errors.iteritems() if key in fields])
final_errors = {} # here the author of this code totally lost me.
for key, val in errors.iteritems():
if '__all__' in key:
final_errors[key] = val
elif not isinstance(formfields[key].field, forms.FileField):
html_id = formfields[key].field.widget.attrs.get('id') or formfields[key].auto_id
html_id = formfields[key].field.widget.id_for_label(html_id)
final_errors[html_id] = val
data = {
'valid': False or not final_errors,
'errors': final_errors,
}
json_serializer = LazyEncoder() # Why does the result have to be returned in json?
return HttpResponse(json_serializer.encode(data), mimetype='application/json')
validate = require_POST(validate) # a decorator that requires a post to submit
LazyEncoder
class LazyEncoder(JSONEncoder):
def default(self, obj):
if isinstance(obj, Promise):
return force_unicode(obj)
return obj
form_class = kwargs.pop('form_class')
This is simply pulling the keyword argument, form_class, that was passed in via the URL conf.
(r'^SOME/URL/$', 'ajax_validation.views.validate',
{'form_class': ContactForm}, # this keyword argument.
'contact_form_validate')
BaseFormSet is simply the formset class doing the work behind the scenes. When you don't know, search the source! grep -ri "baseformset" . It's an invaluable tool.
Take a look at at django.forms.formsets to see how formset_factory produces new "formset" classes based on the BaseFormSet, hence the factory part!
I am guessing that this is for when there are multiple form submitted for validation
Yes, that's exactly what a formset is for (dealing with multiple forms)
I think he is looping over all fields and checking for error. what does add_prefix () return? and what is formfields[]?
Yes, that would be looping through the field names.
add_prefix() is for prefixing form field names with a specific form. Because a formset repeats form elements multiple times, each field needs a unique prefix, such as 0-field1, 1-field1, etc.
formfields is just an empty dictionary defined a few lines above.
what is the 'all'?
__all__ is defined at the top of django.forms.forms
NON_FIELD_ERRORS = '__all__'
It's just what non field specific errors (such as constraints across 2 fields) are stored under in the errors dictionary as opposed to errors[fieldname].
I am having a hard time understanding what this if statement does.
The author has left a note:
# if fields have been specified then restrict the error list
if request.POST.getlist('fields'):
It's checking if you specified any specific fields to validate in your URLConf, this is not django but ajax_validation.
You can see that he's overwriting his errors dictionary based on only the fields specified, thus passing on the validation only for those fields.
errors = dict([(key, val) for key, val in errors.iteritems() if key in fields])
here the author of this code totally lost me.
The author has mapped a custom errors and fields dictionary to specific field names with prefixes, (as opposed to the usual FormSet with each form having its own errors dictionary, unaware of the formset itself) which he presumably uses in the AJAX response to validate all fields.
Normally, you can iterate over a formset and go through the errors on a form by form basis, but not so if you need to validate all of them through ajax.
The line pulling html_id should be straight forward most of the time, but it's there because form widgets CAN add interesting things to the end of the ID's based on whether or not the widget is a radio select for example.
From source comments :
# RadioSelect is represented by multiple <input type="radio"> fields,
# each of which has a distinct ID. The IDs are made distinct by a "_X"
# suffix, where X is the zero-based index of the radio field. Thus,
# the label for a RadioSelect should reference the first one ('_0').
Why does the result have to be returned in json?
Because it's an ajax request and javascript easily eats json.
2- could you go through these lines of code...
extra_args_func = kwargs.pop('callback', lambda request, *args, **kwargs: {})
Either return a keyword argument named 'callback' (which if passed in, is supposed to be a function that accepts request and return a dictionary), and if it wasn't, return a lambda function that only returns an empty dictionary.
I'm not sure what the specific use is for the extra context. You could use it to run arbitrary snippets of code without modifying or subclassing ajax_validation...
It might help you to run this code, and put a debugger breakpoint in somewhere so you can step through and examine the variables and methods. You can do this by simply putting this line where you want to break:
import pdb; pdb.set_trace()
and you will be dumped into the debugger in the console.