23👍
I suspect that the __unicode__
method for the Profile model instance, or the repr
thereof is set to return a value other than self.id
. For example, I just set this up:
# models.py
class Profile(models.Model):
name = models.CharField('profile name', max_length=10)
def __unicode__(self):
return u'%d' % self.id
class Plan(models.Model):
name = models.CharField('plan name', max_length=10)
profile = models.ForeignKey(Profile, related_name='profiles')
def __unicode__(self):
return self.name
# forms.py
class PlanForm(forms.ModelForm):
profile = forms.ModelChoiceField(queryset=Profile.objects.all(),
widget=forms.HiddenInput())
class Meta:
model = Plan
# views.py
def add_plan(request):
if request.method == 'POST':
return HttpResponse(request.POST['profile'])
profile = Profile.objects.all()[0]
form = PlanForm(initial={'profile':profile})
return render_to_response('add_plan.html',
{
'form':form,
},
context_instance=RequestContext(request))
With that, I see PlanForm.profile rendered thus in the template:
<input type="hidden" name="profile" value="1" id="id_profile" />
15👍
Hmm…
This might actually be a security hole.
Suppose a malicious attacker crafted a POST (say, by using XmlHttpRequest from FireBug) and set the profile term to some wacky value, like, your profile ID. Probably not what you wanted?
If possible, you may want to get the profile from the request object itself, rather than what’s being submitted from the POST values.
form = PlanForm(request.POST)
if form.is_valid():
plan = form.save(commit=False)
plan.owner = request.user.get_profile()
plan.save()
form.save_m2m() # if neccesary
- AttributeError: 'RelatedManager' object has no attribute 'remove'
- How is pip install using git different than just cloning a repository?
- Django session expiry?
- Django annotate specific keys in json fields
9👍
When you assign a Profile object to the form, Django stringifies it and uses the output as the value in the form. What you would expect though, is for Django to use the ID of the object instead.
Luckily, the workaround is simple: Just give the form primary key values of the Profile objects instead:
form = PlanForm(initial={'profile': profile.pk})
On the other end, when you’re working with bound forms, however, they work much more sensibly:
form = PlanForm(request.POST)
if form.is_valid():
print form.cleaned_data['profile'] # the appropriate Profile object
- Retrieving the 'many' end of a Generic Foreign Key relationship in Django
- How to get object from PK inside Django template?
2👍
There’s usually no need to put related object into form field. There’s a better way and this is specifying parent id in form URL.
Let’s assume you need to render a form for new Plan object and then create one when form is bubmitted. Here’s how your urlconf would look like:
(r"/profile/(?P<profile_id>\d+)/plan/new", view.new_plan), # uses profile_id to define proper form action
(r"/profile/(?P<profile_id>\d+)/plan/create", view.create_plan) # uses profile_id as a Plan field
And if you’re changing existing object, all you need is plan_id, you can deduce any related record from it.
- Django: correctly retrieve data where date and time are greater than now
- How do you use Django-filter's '__in' lookup?
2👍
Since ModelChoiceField inherits from ChoiceFIeld, you should use the MultipleHiddenInput widget for this:
class PlanForm(forms.ModelForm):
owner = forms.ModelChoiceField(
queryset=Profile.objects.all(),
widget=forms.MultipleHiddenInput())
class Meta:
model = Plan