How to get an auto modified field in django model? - django

Say I have a model User, which has a credits field (IntegerField). When a user registers, I will set the credits field to 0, and I will update the credits for certain events.
I don't want the user know there is a field like this in the db table.
What attribute should I set to the field?

To accomplish the defaulting to 0 part, you can simply use the default argument of the model field.
For the part where you don't want your users to know about the field, you have a couple choices.
Solution 1: Field.editable
Defining your field as follows will cause the field to never show up in a model form.
credits = models.IntegerField(default=0, editable=False)
Downsides
You won't be able to edit the field's value in the admin
Form validation will never take this field into account (e.g., def clean_credits(self): won't run)
Solution 2: ModelForm.exclude|fields
Creating a ModelForm for the model is something you're going to be doing. You can define an exclude attribute on the form's Meta class, and add "credits" to the list. See the docs linked above. You can instead define fields on the Meta class, and omit "credits". The latter of the two options is considered a better practice, particularly when pertaining to security, and is known as a whitelist.
Downsides
You have to remember to define exclude or fields on every exposed form
Updating the "secret" field
The proper way to handle specifying a "secret" field's value when the field isn't in the form is:
# Inside your view's post method (or FormView.form_valid, if you're using generic views)
instance = form.save(commit=False) # Does everything except INSERT into the database
instance.credits = <however many credits you feel like giving the user>
instance.save()
If you didn't do that, and instead just saved the form as-is, the value specified by default would be set to the instance's credits field.

You'll want to use an IntegerField with default=0: credits = models.IntegerField(default=0). Just take care not to show this field to the user in any forms or when displaying the user.
E.g., if you had a ModelForm for User, do not include credits in the fields field of Meta

Related

How to test CheckboxSelectMultiple in save

I have a form (ModelForm) in Django, where I am adding a field for users in the init method as so:
self.fields["users"] = forms.ModelMultipleChoiceField(
queryset=users, widget=forms.CheckboxSelectMultiple, required=False,label="Add Designer(s)"
)
In the save method how I can iterate over the queryset for this field, however, I do not know how I can test if the particular model has been selected/checked. Help, please.
EDIT:
Let's say that you have a form where you want to be able to add users to a certain project, I set the users field as above (also usedMultipleChoiceField) but my real question is how do you determine the state of those checkboxes (which users should be added)?
Managed to fix it using MultipleChoiceField instead of ModelMultipleChoiceField. Then populated the choices with existing event IDs and passed it to the template.
In forms:
choices = forms.MultipleChoiceField(widget = forms.CheckboxSelectMultiple())
In views:
form.fields['choices'].choices = [(x.eventID, "Event ID: " + x.eventID) for x in unapproved]
Had to change some of the logic for finding and editing Event objects too.
The Django documentation states that a ModelMultipleChoiceField normalizes to a QuerySet of model instances. That means in your example, it will only return the users that have been checked. If none have been checked, it will return an empty QuerySet.
If you are overriding your ModelForm save method, you could include something like this:
selected_users = self.cleaned_data.get('users')
for user in selected_users:
project_users.add(user)

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).

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>

Django: Change the DOM id at form field level

I understand that, by default, Django auto-populates id for each form field upon rendering with the format id_for_%s. One can modify the format by providing the auto_id argument with a different format as its value to the Form constructor.
That's not exactly what I am looking for, however. What I want to accomplish is changing the id of just one of the many fields in my form. Also, the solution should not break the use of form = MyForm(request.POST).
PS. MyForm is a model form, so each id is derived from its corresponding Model field.
Thanks for helping out.
The forms framework appears to generate labels here:
def _id_for_label(self):
"""
Wrapper around the field widget's `id_for_label` class method.
Useful, for example, for focusing on this field regardless of whether
it has a single widget or a MutiWidget.
"""
widget = self.field.widget
id_ = widget.attrs.get('id') or self.auto_id
return widget.id_for_label(id_)
id_for_label = property(_id_for_label)
Which means you can just supply your field widget with an "id" key to set it to whatever you'd like.
foo = forms.CharField(widget=forms.TextInput(attrs={'id': 'foobar'}))
Or override init and set the attrs after form initialization.
I don't see how this could break a form as django's forms framework isn't ever aware of HTML ids (that data is not passed to the server...)

Updating user information for an extend user field - Django

I'm trying to create an update_profile form. This form will be able to
update extended user information that is not in the original form.
So, I have a form that allows you to create an account. There a lot of
other fields that aren't listed in this form. The rest of these fields
will be found when the user actually logs in and attempts to edit their profile. What I can't figure out
is how to make the save function in that class that allows them to update this information.
Like in the extended user class that I made, I have a save function
that creates a user and saves it. But I don't want to create another
user with this form. I simply want to update the current authenticated
user. I thought there would be an update_user-type function in the
UserManager(), but there isn't. I tried googling and didn't come up
with much. Help Please?
Use ModelForm to create a form to your custom UserProfile model with a subset of the fields:
Using a subset of fields on the form
In some cases, you may not want all
the model fields to appear on the
generated form. There are three ways
of telling ModelForm to use only a
subset of the model fields:
Set editable=False on the model field.
As a result, any form created from the
model via ModelForm will not include
that field.
Use the fields attribute
of the ModelForm's inner Meta class.
This attribute, if given, should be a
list of field names to include in the
form. The order in which the fields
names are specified in that list is
respected when the form renders them.
Use the exclude attribute of the
ModelForm's inner Meta class. This
attribute, if given, should be a list
of field names to exclude from the
form.
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#using-a-subset-of-fields-on-the-form