from list to select menu in django - python

I thought I had it figured out but now I'm missing something.
First I have a QuerySet, records
records = Record.objects.all()
Now I want to make this into a list of one of the columns of the table, columnA
alist = records.values_list('columnA')
And then I want to pass this list in as a parameter to a custom form.
FilterForm(alist)
Here's my form
class FilterForm(forms.Form,list):
numbers = forms.ChoiceField(list)
but keep getting an error that 'type' object is not iterable. I'm not sure the problem has to do with the passing of the list because when I try and run this code in the shell, I get the error message when just importing the FilterForm
EDIT: I changed my FilterForm so now it looks like this.
class FilterForm(forms.Form):
def __init__(self,numbers):
number = forms.ChoiceField(numbers)
so now I think it's more evident what I'm trying to do, pass in a list to the FilterForm. However when I render my template and pass the form, no form field shows up. No error message though
EDIT EDIT: Also tried this, saw it online
class FilterForm(forms.Form):
number = forms.ChoiceField()
def __init__(self,numbers):
super(FilterForm,self).__init__()
self.fields['number'].choices=numbers
but error:
Exception Type: TemplateSyntaxError
Exception Value:
Caught ValueError while rendering: need more than 1 value to unpack

The problem is the word list in this line:
numbers = forms.ChoiceField(list)
You need to provide a specific list to ChoiceField.

Here's an error:
class FilterForm(forms.Form,list):
numbers = forms.ChoiceField(list)
You make FilterForm a subclass of forms.Form and list; then you expect list to be available as argument to the ChoiceField.
I think you are looking for dynamic ChoiceFields.
Further reading:
django model/modelForm - How to get dynamic choices in choiceField?

Related

Django: Trying to create a user score system

So instead of making this into a new app or actually add it to the User model I want to just calculate this in the view. So here are two lines of code that I've added to get the number of posts a user has created and then multiplying it by 10 (the value I'm giving to adding a post) in the view and then passing it into the template. However, I am getting an error.
Not sure if I'm going about this in the best way, but heres what I have.
Code the in the view:
posts = UserPost.objects.filter(author=user)
posts_count = posts.len() * 10
The error:
AttributeError at /user/2/
'QuerySet' object has no attribute 'len'
I also tried with .count instead of .len()
Try this:
posts = UserPost.objects.filter(author=user)
posts.count()

Django how to query objects one by one

I have to query an object from a model, this object is called "exercise" and has many fields(title, body, answers, etc.) I need to get "exercise objects" one by one with all their fields, do some rendering on them and give back a pdf of the exercise as result.
The problem is, if I do:
exercises = ExerciseModel.objects.all()
I get all of them. If I do:
some_exercises = ExerciseModel.objects.filter(something=something)
I get "some of them" depending on filter. And if i do:
exercise = ExerciseModel.objects.get()
I get
error get() returned more than one exercise
How can I get them one by one? I must be able to use them as input for another function.
If you need to perform the task on only 1 exercise, use get() instead. In such case, you need a criteria to make sure get() will return 1 and only 1 result.
Example:
ex = ExerciseModel.objects.get(pk=123)
From the doc:
Returns the object matching the given lookup parameters, which should be in the format described in Field lookups.
get() raises MultipleObjectsReturned if more than one object was found. The MultipleObjectsReturned exception is an attribute of the model class.
get() raises a DoesNotExist exception if an object wasn’t found for the given parameters. This exception is an attribute of the model class.
When you have a QuerySet with filters that ensure the underlying SQL request will return only 1 row, you can call get() without argument on the QuerySet. This return the row as model instance, instead of returning it as a list containing 1 elemnt.
Original answer:
Both filter() and all() methods return a QuerySet instance. You can iterate on it to perform a task for each "exercise" returned by your request
for exercise in ExerciseModel.objects.filter(something=something):
# ... do what you need on your exercise
From the documentation:
A QuerySet is iterable, and it executes its database query the first time you iterate over it. For example, this will print the headline of all entries in the database
What you need is .iterator() which will turn a queryset to an iterator:
exercises = ExerciseModel.objects.all().iterator()
then you get iterate over it in a for loop:
for exercise in exercises:
...
This will improve performance when you have large number of items. However, it has some downsides as well as stated in the docs
Hope it helps!
.get() must return a single object, not a QuerySet instance. If you want to get a single exercise then you must pass a parameter to the .get instance. For example, retrieving an object by name would require the following code:
exercise = ExerciseModel.objects.get(name="an_exercise")
If you want to iterate through all the objects without actually retrieving a QuerySet containing the objects, you could use the following code:
for i in range(Exercise.objects.all().count()):
exercise = Exercise.objects.get(pk=i)
... operate on object ...

How to update form with errors in Django?

I'm trying to write an is_valid method for my forms and I'm using this general strategy:
def is_valid(self):
form = super(UserCreateForm, self).is_valid()
for f, error in self.errors.iteritems():
if f!= '__all__':
self.fields[f].widget.attrs.update({'class': 'error', 'value': strip_tags(error)})
return form
I want to update the form fields' attributes if I get an error with helpful attributes. But I already have class attributes for the fields (using Bootstrap, so something like 'class':'form-control'); I want the error to replace them. However, when I fail the validation and actually get an error, Django complains saying can't concatenate str and errorList. I'm a bit new to Django, so I'm not sure what is going on here.
The way i do this is, have the the errors checked at all the individual divs and display bootstrap's .error class if i find a error.
Eg:{% if form.error %}
Like that you check it with every filed name.
Note: There might be better ways to do it, but i have been using this for a long time now and has worked fine.

How to properly validate a MultipleChoiceField in a Django form

I have a MultipleChoiceField representing US states, and passing a GET request to my form like ?state=AL%2CAK results in the error:
Select a valid choice. AL,AK is not one of the available choices.
However, these values are definitely listed in the fields choices, as they're rendered in the form field correctly.
I've tried specifying a custom clean_state() method in my form, to convert the value to a list, but that has no effect. Printing the cleaned_data['state'] seems to show it's not even being called with the data from request.GET.
What's causing this error?
from django import forms
class MyForm(forms.Form):
state = forms.MultipleChoiceField(
required=False,
choices=[('AL','Alabama'),('AK','Alaska')],
)
MultipleChoiceFields don't pass all of the selected values in a list, they pass several different values for the same key instead.
In other words, if you select 'AL' and 'AK' your querystring should be ?state=AL&state=AK instead of ?state=AL%2CAK.
Without seeing your custom clean_state() method I can't tell you what's going wrong with it, but if the state field isn't valid because the querystring is wrong then 'state' won't be in cleaned_data (because cleaned_data only holds valid data).
Hopefully that helps. If you're still stuck try adding a few more details and I can try to be more specific.

How to append error message to form.non_field_errors in django?

I have a form with several fields. I have separate validation checks for each field, done via the forms validation. I however also need to check if few fields are filled in before redirecting the user to a different view. I was hoping I could somehow append the error to forms.non_field_errors as it is not for a particular field , but I am not sure what the right syntax for this would be. I have checked online and found..
form.errors['__all__'] = form.error_class(["error msg"])
This displays the error message, but it seems to mess up the other pages as well and displyas the error message if I click on anything else.
I tried
form._errors[NON_FIELD_ERRORS] = form.error_class()
This causes a 'NoneType' object has no attribute 'setdefault' error for me.
I have tried
form.non_field_errors().append("Please complete your profile in order to access the content.")
This doesn't seem to do anything and I cant see the error message on the view.
What would be the best way to do this? Ideally I dont' want to do it in the form's clean method. I feel like I should be able to append an error to the form in the view.
Call full_clean(), this should initialize form._errors. This step is critical, if you don't do it, it won't work.
Make the error list, it takes a list of messages, instanciate it as such: error_list = form.error_class(['your error messages'])
Assign the error list to NON_FIELD_ERRORS, you have to import NON_FIELD_ERRORS from django.forms.forms, then assign as such: form._errors[NON_FIELD_ERRORS] = error_list
Here is a demonstration from a shell:
In [1]: from bet.forms import BetForm
In [2]: from django.forms.forms import NON_FIELD_ERRORS
In [3]: form = BetForm()
In [4]: form.full_clean()
In [5]: form._errors[NON_FIELD_ERRORS] = form.error_class(['your error messages'])
In [6]: form.non_field_errors()
Out[6]: [u'your error messages']
This is a bit out-dated but i recently ran into the same question and wanted to shed some further light on this for future readers.
As of Django 1.6+ the errors dictionary is stored as form.errors and not form._errors
If you instantiate form.is_valid(), it is the equivalent of running full_clean()
NON_FIELD_ERRORS isn't necessary to import, you can simply refer to its default dictionary key of __all__
Example:
if form.is_valid():
form.errors['__all__'] = form.error_class(['Your Error Here!'])
On form there is method add_error.
class ExampleForm(forms.Form) :
def clean(self) :
self.add_error(None, "The __all__ error message")
return super().clean()
The first param of add_error() function is about the refered fields.
If the field is None the add_error() function will considere that the error is a form_error.
The clean() method is a hook called by _clean_form().
Then the _clean_form() function is called by full_clean(). See more: full_clean() source
self._errors.setdefault('__all__', ErrorList()).extend([""])

Categories