Django KeyError when getting an object with a keyword for a field name - django

I wish to get an object in the following fashion:
Collection.objects.get(name='name', type='library', owner=owner, parent=parent)
Unfortunately type is a keyword as thus creates the following error:
KeyError at /forms/create_library
type
Is there a way to disambiguate the meaning of the word type to allow me to specify a field of that name?

Not tested:
Collection.objects.filter(
name__exact='name',
type__exact='library',
owner__exact=owner,
parent__exact=parent)
Query docs: http://docs.djangoproject.com/en/dev/topics/db/queries/
Also consider naming your field differently, mainly not with the same name as a builtin.

OK it turns out the problem was elsewhere. I was doing this in a form and thus using the self.cleaned_data dictionary of input values.
I was attempting to retrieve self.cleaned_data['type'] where in my previous simplification I stated the string 'library'. This was not in fact in the cleaned data of the form and thus threw a KeyError.

Related

Django in_bulk() raising error with distinct()

I have the following QuerySet:
MyModel.objects
.order_by("foreign_key_id")
.distinct("foreign_key_id")
.in_bulk(field_name="foreign_key_id")
foreign_key_id is not unique on MyModel but given the use of distinct should be unique within the QuerySet.
However when this runs the following error is raised:
"ValueError: in_bulk()'s field_name must be a unique field but 'foreign_key_id' isn't."
According to the Django docs on in_bulk here it should be possible to use in_bulk with distinct in this way. The ability was added to Django in response to this issue ticket here.
What do I need to change here to make this work?
I'm using Django3.1 with Postgres11.
As the documentation of in_bulk(…) says:
(…)
Changed in Django 3.2:
Using a distinct field was allowed.
Since you use django-3.1, this will thus not work, you will thus have to upgrade your program to django-3.2.

Django empty_label for ModelMultipleChoiceField. Multiple values for keyword argument 'empty_label'

I'm trying to put a placeholder in a Select2 field, by putting empty_label in the field. Now i get the error:
TypeError: __init__() got multiple values for keyword argument 'empty_label'
Here is my code:
self.fields['work_types'] = ModelMultipleChoiceField(
queryset=WorkTypes.objects.filter(
white_label_client=logged_in_user.white_label_client,
deleted=False),
empty_label='Type',
required=False)
What do i have to change?
According to the comments here, it is a current bug in Django. One of the users said:
"Looking at it, I would say that this is by design. You shouldn’t use an empty label on a multiple choice field. Perhaps this should be clarified in the docs.
Saying that, if you really want an empty label on a multiple choice field, you could create your own class that initializes empty_label however you want it."
Further explanation
"Well, it is raising an error. It’s a Python error. Basically, you were passing a keyword argument (empty_label), and the class was passing the same keyword argument called empty_label. Expanded out, this is what was happening:"
field = forms.ModelMultipleChoiceField( queryset = Imodelclass.objects.all(), empty_label='------------' ) = ModelMultipleChoiceField(queryset= Imodelclass.objects.all(), empty_label=None, empty_label='------------')
"When you read the error, you see that is actually very clear in this context: You passed two arguments for the same keyword."
"I think it would be wise to mention this in the documentation; perhaps even providing a rationale why ModelMultipleChoiceField should not have an empty label. But if there is no rationale behind it, then the clear solution is to do exactly as you did: remove the empty_label keyword argument from the super call."

Django call cleaned_data on all fields

Is there a way to call cleaned_data on all fields with some function instead of individually calling it for each field?
Also, why do we even need to call cleaned_data?
I am not sure if I need it here... I am using a for loop to save a formset, but it only saves the last one. Here is the code
for instance in form:
tmp = instance.save(commit=False)
# it throws an error when I try to do tmp[foreign_key] = other_model
setattr(tmp, foreign_key, other_model)
tmp.save()
What are you hoping for? You don't ever call it. cleaned_data gets populated upon validating the form.
form.is_valid() populates form.cleaned_data, which is a dictionary storing all data "cleaned" i.e. validated and converted to their python types.
I don't think one can make data much more accessible than a dictionary of keys mapped to field names.
As for your latest update, that itself is pretty confusing.
You appear to be setting an attribute on a foreign key in your modelform instance based on a local variable named 'gen_house_form_saved' (which I don't understand as well: if it's in the locals() namespace, and you're not using a dynamic name, why use locals at all).

Django ValidationError - how to use this properly?

Currently there is code that is doing (from with the form):
# the exception that gets raised if the form is not valid
raise forms.ValidationError("there was an error");
# here is where form.is_valid is called
form.is_valid() == False:
response['msg']=str(form.errors)
response['err']='row not updated.'
json = simplejson.dumps( response ) #this json will get returned from the view.
The problem with this, is that it is sending err message to the client as:
__all__"There was an error."
I want to remove the "all" garbage from the error template that is returned. How can I go about doing this? it seems to get added deep in django form code.
It's because the error is not associated with any field in particular, but it's so called non-field error.
If you're only interested in non-field errors, just simply pass this to the response:
response['msg']=str(form.errors['__all__'])
errors is an instance of a subclass of dict with some special rendering code. Most of the keys are the fields of the form, but as the docs describe, raising ValidationError in clean produces an error message that isn't associated with any particular field:
Note that any errors raised by your Form.clean() override will not be associated with any field in particular. They go into a special “field” (called __all__), which you can access via the non_field_errors() method if you need to. If you want to attach errors to a specific field in the form, you will need to access the _errors attribute on the form, which is described later.
https://docs.djangoproject.com/en/dev/ref/forms/validation/
So you can either generate your string representation of the errors differently (probably starting with form.errors.values() or form.errors.itervalues(), and maybe using the as_text method of the default ErrorList class) or associate your error with a particular field of the form as described in the docs:
When you really do need to attach the error to a particular field, you should store (or amend) a key in the Form._errors attribute. This attribute is an instance of a django.forms.utils.ErrorDict class. Essentially, though, it’s just a dictionary. There is a key in the dictionary for each field in the form that has an error. Each value in the dictionary is a django.forms.utils.ErrorList instance, which is a list that knows how to display itself in different ways. So you can treat _errors as a dictionary mapping field names to lists.
If you want to add a new error to a particular field, you should check whether the key already exists in self._errors or not. If not, create a new entry for the given key, holding an empty ErrorList instance. In either case, you can then append your error message to the list for the field name in question and it will be displayed when the form is displayed.
https://docs.djangoproject.com/en/dev/ref/forms/validation/#form-subclasses-and-modifying-field-errors

Invalid keyword argument on new model entry

I have the following model:
class mark(models.Model):
title=models.CharField(max_length=35)
url=models.URLField(max_length=200)
user=models.ManyToManyField(User,blank=True)
and then I use a form to save some data to the db. My code inside the view that saves the data is:
new_mark= mark(url=request.POST['url'],
title=request.POST['title'],
user=request.user)
new_mark.save()
Of course I have all the data validation, login required validation, etc.
When I run this it throws me an unexpected
'user' is an invalid keyword argument for this function
on theuser=request.user) line. Any ideas what might be wrong?
Please provide the whole traceback and make sure your view has no function named "mark" etc (You probably also want to change mark to Mark to follow Python and Django style guides.) test via print type(mark) before the "new_mark = …" line.
Also I am not 100% sure if a ManyToMany field allows settings data like that, eg try:
new_mark= mark(url=request.POST['url'],
title=request.POST['title'])
new_mark.user.add(request.user)
new_mark.save()
And since it's an m2m field you probably want to rename the field to users.