How to add auto id to django model form - django

My django model by default has an auto generated id field as primary key which is named 'id' by default on my db.
As such my model has a lot of other fields that I am selectively displaying using a Django model form. While doing so I specify 'id' for this auto generated id field but my form does not display or generate this field on HTML at all even though it seems to recognize this as a valid field.
I have also checked by doing an 'all' for fields but this is also not bringing in that specific field. The funny thing is django does seem to recognize this field as 'id' because if I change it to 'Id' or anything else random it immediately gives me an error for example "Unknown field(s) (Id) specified for....." on my forms.py
This 'id' is important as I am using it to link and retrieve related objects using Ajax on client side. If this does not work then I will be forced to use another field as primary key. Any suggestions?

I ended up using a workaround as suggested by 'mastazi' for passing this id as a hidden field.
All I did is access this hidden field and generate it as an html element. Since I am using crispy_forms layout I was able to use an HTML element under Layout.
form_id= self.instance.id
id_hidden = '<input type="hidden" id="form_id" value=' + str(form_id) +' />'
I am not sure if this is a perfect solution but it works.

Related

Does Django Class Based Views automatically assign form value for templates

I use Django 2
This is what my view.py contains
class SchoolCreateView(CreateView):
fields = ("name","principal","location")
model = models.School
The template (html file) used by this view contains the code:
form.instance.pk
And it works. It returns the correct primary key. I don't understand why.
Why does this work when I have not defined the form object in my view? Is the value of form automatically assigned when using CBVs in Django?
Follow up question. I know that form.instance represents a row in the model but what does form itself represent? My current understanding with forms is that it represents request.POST from views.py (basing my knowledge from function views). But that wouldn't make sense because the client has yet to make a POST request since he is still going to create a data entry which will be posted but is not being posted yet.
Pk is a primary key field, which is id by default. if you define other field as primary key, calling pk will return this.
From documentation:
By default, Django gives each model the following field:
id = models.AutoField(primary_key=True)
This is an auto-incrementing primary key.
If you’d like to specify a custom primary key, specify primary_key=True on one of your fields. If Django sees you’ve explicitly set Field.primary_key, it won’t add the automatic id column.
Each model requires exactly one field to have primary_key=True (either explicitly declared or automatically added).

How to rename a field in a Django form?

I have a custom Django widget that renders some HTML that I cannot control, and by default the widget's HTML will has a fixed name attribute using a -, say name="field-name". My problem is that Django expects the name attribute in the HTML to be exactly the same as the variable name of the field in python. But of course in python I cannot name a variable using -.
Is there any way to tell Django to decouple the variable name of the form field from the name in the HTML? In other words, when the user already introduced the data in the field and sends the POST request, can I tell Django that the field field_1 should be reading the value field-name from the requests.POST dictionary?

what field type to use for model field in form in django?

I need to make a model field read only in my form. I do this with the following:
class ActivityEntryForm(forms.ModelForm):
activity = forms.CharField(widget=forms.TextInput(attrs={'readonly':'readonly'}))
duration = forms.IntegerField()
class Meta:
model = CustomerActivity
fields = ('activity', 'duration',)
Activity is an actual model foreign key field to the CustomerActivity model.
This currently displays the Activity Id number. I want it to print the name of the activity.
What field type do I use or how can I show the name instead of the id?
First of all, note that the readonly attribute is not safe to prevent changes. Any nitwit can change the html code nowadays with inspect element etc. built into any browser. For security reasons it's better to exclude the field from the form and present the data in another way, or to have a server-side check to prevent people from changing data.
That's also a good way to solve your question. As an instance of a ModelForm, your form has an instance attribute which holds the actual data related to the object, given that this data exists. Instead of going through an unused form field, use the data form the instance as-is:
<input type="text" readonly="readonly">{% firstof form.instance.activity.name "<default>" %}</input>

Edit/show Primary Key in Django Admin

It appears Django hides fields that are flagged Primary Key from being displayed/edited in the Django admin interface.
Let's say I'd like to input data in which I may or may not want to specify a primary key. How would I go about displaying primary keys in the admin interface, and how could I make specifying it optional?
I also wanted to simply show the 'id' (primary key) within the Django admin, but not necessarily edit it. I just added it to the readonly_fields list, and it showed up fine. IE:
class StudentEnrollmentInline(admin.TabularInline):
model = Enrollment
readonly_fields=('id',)
whereas if I tried to add it to the 'fields' list, Django got upset with me, saying that field didn't exist...
If you explicitly specify the primary key field in your models (with primary_key=True), you should be able to edit it in the admin.
For Django models created via ./manage.py syncdb the following primary key field is added automatically:
id = models.AutoField(primary_key=True)
if you change (or add) that to your model explicitly as an IntegerField primary key, you'll be able to edit it directly using the admin:
id = models.IntegerField(primary_key=True)
But as others pointed out, this is a potential minefield...
To show the primary key, which by default will have a column name of "id" in the database - use "pk"
def __str__(self):
return '{} - {} ({})'.format(self.pk, self.name, self.pcode)
It doesn't make sense to have an optional primary key. Either the PK is an autoincrement, in which case there's no need to edit it, or it's manually specified, in which case it is always required.
Why do you need this?
In django documentation, there is a short sentence about that, which is not clear:
If neither fields nor fieldsets options are present, Django will default to displaying each field that isn't an AutoField and has editable=True, in a single fieldset, in the same order as the fields are defined in the model.
Reason is, django do not allow you to edit an AutoField by any means (and that is the right thing since it is an auto increment value and should not be edited). #mnelson4's answer is a good approach to display it.
The answer with the highest votes didn't work for me. I needed a getter.
class StudentEnrollmentInline(admin.TabularInline):
model = Enrollment
readonly_fields=('student_enrollment_id',)
def student_enrollment_id(self, obj):
return obj.id
Using django 1.11

Model Formset Issue

I have a model for which the need is to show the form multiple times. I have used it under a modelformset. I seem to have a problem with the id of this model which is also the primary key for the model.
I prepopulate the formset with data which I wish to edit.
But whenever I click on submit it refreshes the page back with an error saying '(Hidden field id) with this None already exists.'
This error comes specifically for the 'id' field which is hidden
<input type="hidden" id="id_form-0-id" value="2972" name="form-0-id"/>
This is the snippet from the template. (I got it from firebug)
What could the issue possibly be since the form is invalid I am not able to save the data.
ProfilesFormSet = modelformset_factory(Profile,exclude = ( <items spearated by commas>), extra=0)
profile_form_set = ProfilesFormSet(queryset = Profile.objects.filter(userprofile=userprofile).order_by('-modified_on'))
This is the code snippet.
If you're using PostgreSQL and any version of Django prior to 1.1beta, and your model does not have a default ordering defined, I think you're probably seeing the bug related to inconsistent ordering of objects returned from the database (see Django Trac tickets 9076, 9758, 10163 among others).
Try setting a default ordering on the model:
class Meta:
ordering = ('some_field',)
See if that fixes it.
I believe this error is caused by one of the following:
The Django form object you are using inside the formset does not include the primary key (id) of the model. However, since you are using modelformset_factory this shouldn't be the case (you also wouldn't be getting that error message).
The HTML form in your template does not include the primary key, even as a hidden field. Make sure you have {{ form.id }} or something like that in your template, inside the {{ for form in formset }} loop.
I can't think of any more reasons at the moment, but I'm sure they are all going to be related to the form POST'ed back from the browser client is missing the id field somehow.