Use variables when saving objects in Django - python

In Django, is there a way to identify which attribute of an object I want to edit by using a POST/GET variable instead of explicitly naming it?
For example, I want to do this:
def edit_user_profile(request):
field_to_edit = request.POST.get('id')
value = request.POST.get('value')
user = User.objects.get(pk=request.user.id)
user.field_to_edit = strip_tags(value);
user.save()
instead of this:
def edit_user_profile(request):
value = request.POST.get('value')
user = User.objects.get(pk=request.user.id)
user.first_name = strip_tags(value);
user.save()

Gabi's answer is exactly what you want. You could use setattr instead though:
setattr(user, field_to_edit, strip_tags(value))
Which is (very very slightly!) more intuitive.

You can use the getattr function:
getattr(user, field_to_edit) = strip_tags(value)

Related

too many values to unpack [Django]

def index(request):
expiring_list = probe.objects.filter("isExpired=True")
output = ', '.join([p.serial for p in expiring_list])
return HttpResponse(output)
isExpired is a Boolean function. How should I modify the filter so that the filter does not raise a ValueError?
You are making the query in a wrong format.
Your query should be of the form:
expiring_list = probe.objects.filter(isExpired = True)
This was the query you needed to make in case isExpired was your model field. But since you say its a function, assuming that function is inside the class you need to get all the objects in the following way:
expiring_list = []
objects = probe.objects.all()
for obj in objects:
if obj.isExpired() == True:
expiring_list.append(obj)
The expiring_list will now contain all the objects of the model probe where isExpired function returns True
I think isExpired is not a field in your models, as reference to your previous question Refresh a field from another table [Django]
I think exp_date is the field which you are looking for.
Try this:
import datetime
def index(request):
expiring_list = probe.objects.filter(exp_date__lt=datetime.date.today())
output = ', '.join([p.serial for p in expiring_list])
return HttpResponse(output)

iterate over django form results (not in a template)

I am trying to iterate over form results and I can't help but think that I am re-inventing the wheel here.
filterlist = []
if request.POST:
form = FilterForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.iteritems():
filterlist.append(key)
filterlist.append(value)
This works, but seems very awkward and creates lots of other problems. For example the values come back with u' so I have to use value.encode("utf8") but then if a value is None it throws in error. So now I have to check if it is None, if not then encode. There has to be a better way.
EDIT: What I am trying to do.
I am trying to filter what is shown on a page. The problem I am running into is that if a value is empty (the user don't fill the box because they only want to filter against one object) then I get no results. For example a user wants to search for all books by the author name "Smith" but doesn't want to search against a genre.
results = Books.objects.filter(author=author, genre=genre)
The user would get no results because this is an AND search. But, if a user put in "Smith" for the author and "mystery" for the genre then it works exactly like I want it to, only giving results where both are true.
So, I am trying to eliminate the empty stuff by iterating over the form results. Like I said I am probably re-inventing the wheel here.
In Python 3 use:
for key, value in form.cleaned_data.items():
If the field names are the same in the model and the form, try this:
filter = {}
if request.method == 'POST':
form = FilterForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.iteritems():
if value:
filter[key] = value
results = Books.objects.filter(**filter)
Python is one of the few languages having named parameters. You can assemble a dict with the non-empty form fields and pass it to the filter method using the kwargs unpacking operator **.
For example:
kwargs = {"author": "Freud"}
results = Books.objects.filter(**kwargs)
Is the same as:
results = Books.objects.filter(author="Freud")
I think the problem is that by default the Model form is not valid if a form field does not have a value entered by the user, if you don`t require the field every time from the user you need to set the required field to false in the ModelForm class in forms.py as shown in the code below. Remember that the field is set false only in the model form not in the model itself
class myForm(forms.ModelForm):
myfield_id = forms.CharField(required=False)
myfield_foo = forms.CharField(required=False)
myfield_bar = forms.CharField(required=False)
myfield_name = forms.CharField(required=False)
class Meta:
model = myModel
exclude = ('myfield_ex','myfield_file')
fields = ['myfield_id','myfield_foo','myfield_bar','myfield_name',]
After you have the form entered by the user what you need is use the Q object which can be used to create complex queries as described in the manula page here
https://docs.djangoproject.com/en/1.7/topics/db/queries/#complex-lookups-with-q
A simple example code would look like
if form.is_valid():
qgroup = []
for key,value in form.cleaned_data.iteritems():
if value:
q_name = Q(**{"%s"%format(filterKey[key]) : value})
qgroup.append(q_name)
q = None
# can use the reduce as shown here qgroup = reduce(operator.or_, (Q(**{"{0}".format(filterKey[key]): value}) for (key,value) in form.cleaned_data.iteritems()))
for key,value in form.cleaned_data.iteritems():
if value:
q_name = Q(**{"%s"%format(filterKey[key]) : value})
qgroup.append(q_name)
for x in qgroup:
q &= x ### Or use the OR operator or
if q:
resultL = myModel.objects.filter(q).select_related()
The filterKey can look something on the lines of
filterKey = {'myfield_id' : "myfield_id",
'myfield_foo' : "myfield_foo__icontains",
'myfield_bar' : "myfield_bar__relative_field__icontains",
}

change a form value before validation in Django form

I have a django form and on my view function I do this :
search_packages_form = SearchPackagesForm( data = request.POST )
I would like to overwrite a form field called price which is decleared as such :
price = forms.ChoiceField( choices = PRICE_CHOICES, required = False,widget = forms.RadioSelect )
I would like to overwrite the form field before calling search_packages_form.is_valid()
I thought of doing :
search_packages_form.data['price'] = NEW_PRICE
But it does not work. Any ideas ?
Probably not the Django way but based on https://stackoverflow.com/a/17304350/2730032 I'm guessing the easiest way to change your form value before validation is to do something like the following:
def search_packages_view(request):
if request.method == 'POST'
updated_request = request.POST.copy()
updated_request.update({'price': NEW_PRICE})
search_packages_form = SearchPackagesForm(updated_request)
if search_packages_form.is_valid():
# You're all good
This works but I'd be interested if anyone has another way that seems more in line with Django, or if there isn't: then an explanation about why.
one trick for what you want is to do it like this:
changed_data = dict(request.POST)
changed_data['price'] = NEW_PRICE
search_packages_form = SearchPackagesForm(data = changed_data)
My solution is build on an earlier proposal. It is a working solution, which can be used in several cases.
#Milad Khodabandehloo
had a tricky solution to solve the problem.
changed_data = dict(request.POST)
changed_data['price'] = NEW_PRICE
search_packages_form = SearchPackagesForm(data = changed_data)
as #The EasyLearn Academy commented: it does not allow you to access actual data submitted in form.
This is because the request.POST is immutable.
But there is a solution to the problem - just have to be more tricky.
This solution is only good if a reference to the object is enough for the certain cause. It leaves the object itself the same.
# write object to variable (data)
data = request.POST
# set to mutable
data._mutable = True
# modify the values in data
data[modified_field] = new_value
# set mutable flag back (optional)
data._mutable = False
Hope it's useful!
form.is_valid() runs through your form's (and model's in case of a ModelForm) clean method's, returning True or False
If you plan on changing form data you can do it within the general clean method or at field level, e.g.
class YourForm(DerivingClass):
# regular stuff
def clean_<ATTR>(self):
# here
return self.cleaned_data
def clean(self):
# or here
return super(YourForm, self).clean()

How to initialize django-form data type field from a given choices?

First of all: I am not able to find out the proper Title of this question.
Anyhow the question is:
I have to fill a form at template and the fields of this form are user dependent. For example you passes integer (integer is not a datatype) as a parameter to the method and it should returns like this:
fileds = forms.IntegerField()
If you pass bool then it should like this:
fields = forms.BooleanField()
So that i can use them to create my form. I tried with this code but it returns into the form of string.
Some.py file:
choices = (('bool','BooleanField()'),
('integer','IntegerField()'))
def choose_field():
option = 'bool' # Here it is hardcoded but in my app it comes from database.
for x in choices:
if x[0]==option:
type = x[1]
a = 'forms'
field = [a,type]
field = ".".join(field)
return field
When i print the field it prints 'forms.BooleanField()'. I also use this return value but it didn't work. Amy solution to this problem?
The simpliest way is to create your form class and include fields for all possible choices to it. Then write a constructor in this class and hide the fields you don't want to appear. The constructor must take a parameter indicating which fields do we need. It can be useful to store this parameter in the form and use it in clean method to correct collected data accordingly to this parameter.
class Your_form(forms.ModelForm):
field_integer = forms.IntegerField()
field_boolean = forms.BooleanField()
def __init__(self, *args, **kwargs):
option = kwargs["option"]
if option == "integer":
field_boolean.widget = field_boolean.hidden_widget()
else:
field_integer.widget = field_integer.hidden_widget()
super(Your_form, self).__init__(*args, **kwargs)
In your controller:
option = 'bool'
form = Your_form(option=option)

How to get the label of a choice in a Django forms ChoiceField?

I have a ChoiceField, now how do I get the label when I need it?
class ContactForm(forms.Form):
reason = forms.ChoiceField(choices=[("feature", "A feature"),
("order", "An order")],
widget=forms.RadioSelect)
form.cleaned_data["reason"] only gives me the feature or order values or so.
See the docs on Model.get_FOO_display(). So, should be something like :
ContactForm.get_reason_display()
In a template, use like this:
{{ OBJNAME.get_FIELDNAME_display }}
This may help:
reason = form.cleaned_data['reason']
reason = dict(form.fields['reason'].choices)[reason]
This the easiest way to do this: Model instance reference: Model.get_FOO_display()
You can use this function which will return the display name: ObjectName.get_FieldName_display()
Replace ObjectName with your class name and FieldName with the field of which you need to fetch the display name of.
If the form instance is bound, you can use
chosen_label = form.instance.get_FOO_display()
Here is a way I came up with. There may be an easier way. I tested it using python manage.py shell:
>>> cf = ContactForm({'reason': 'feature'})
>>> cf.is_valid()
True
>>> cf.fields['reason'].choices
[('feature', 'A feature')]
>>> for val in cf.fields['reason'].choices:
... if val[0] == cf.cleaned_data['reason']:
... print val[1]
... break
...
A feature
Note: This probably isn't very Pythonic, but it demonstrates where the data you need can be found.
You can have your form like this:
#forms.py
CHOICES = [('feature', "A feature"), ("order", "An order")]
class ContactForm(forms.Form):
reason = forms.ChoiceField(choices=CHOICES,
widget=forms.RadioSelect)
Then this would give you what you want:
reason = dict(CHOICES)[form.cleaned_data["reason"]]
OK. I know this is very old post, but reading it helped me a lot. And I think I have something to add.
The crux of the matter here is that the the model method.
ObjectName.get_FieldName_display()
does not work for forms.
If you have a form, that is not based on a model and that form has a choice field, how do you get the display value of a given choice.
Here is some code that might help you.
You can use this code to get the display value of a choice field from a posted form.
display_of_choice = dict(dateform.fields['fieldnane'].choices)[int(request.POST.get('fieldname'))]
the 'int' is there on the basis the choice selection was a integer. If the choice index was a string then you just remove the int(...)
Im using #Andrés Torres Marroquín way, and I want share my implementation.
GOOD_CATEGORY_CHOICES = (
('paper', 'this is paper'),
('glass', 'this is glass'),
...
)
class Good(models.Model):
...
good_category = models.CharField(max_length=255, null=True, blank=False)
....
class GoodForm(ModelForm):
class Meta:
model = Good
...
good_category = forms.ChoiceField(required=True, choices=GOOD_CATEGORY_CHOICES)
...
def clean_good_category(self):
value = self.cleaned_data.get('good_category')
return dict(self.fields['good_category'].choices)[value]
And the result is this is paper instead of paper.
Hope this help
I think maybe #webjunkie is right.
If you're reading from the form from a POST then you would do
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
contact = form.save()
contact.reason = form.cleaned_data['reason']
contact.save()
confirm that Ardi's and Paul's response are best for forms and not models. Generalizing Ardi's to any parameter:
class AnyForm(forms.Form):
def get_field_name_display(self, field_name):
return dict(self.fields[field_name].choices[self.cleaned_data[field_name]]
Or put this method in a separate class, and sub-class it in your form
class ChoiceFieldDisplayMixin:
def get_field_name_display(self, field_name):
return dict(self.fields[field_name].choices[self.cleaned_data[field_name]]
class AnyCustomForm(forms.Form, ChoiceFieldDisplayMixin):
choice_field_form = forms.ChoiceField(choices=[...])
Now call the same method for any Choice Field:
form_instance = AnyCustomForm()
form_instance.is_valid()
form_instance.get_field_name_display('choice_field_form')

Categories

Resources