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()
Related
I haven't had much luck finding other questions that helped with this, but apologies if I missed something and this is a duplicate.
I'm trying to add to some ManyToMany fields, without having to explicitly type out the names of the fields in the code (because the function I'm working on will be used to add to multiple fields and I'd rather not have to repeat the same code for every field). I'm having a hard time using ._meta to reference the model and field objects correctly so that .add() doesn't throw an "AttributeError: 'ManyToManyField' object has no attribute 'add'".
This is simplified because the full body of code is too long to post it all here, but in models.py, I have models defined similar to this:
class Sandwich(models.Model):
name = models.CharField(max_length=MAX_CHAR_FIELD)
veggies = models.ManyToManyField(Veggie)
meats = models.ManyToManyField(Meat)
class Veggie(models.Model):
name = models.CharField(max_length=MAX_CHAR_FIELD)
class Meat(models.Model):
name = models.CharField(max_length=MAX_CHAR_FIELD)
Once instances of these are created and saved, I can successfully use .add() like this:
blt = Sandwich(name='blt')
blt.save()
lettuce = Veggies(name='lettuce')
lettuce.save()
tomato = Veggies(name='tomato')
tomato.save()
bacon = Meat(name='bacon')
bacon.save()
blt.veggies.add(lettuce)
blt.veggies.add(tomato)
blt.meats.add(bacon)
But if I try to use ._meta to get blt's fields and add to them that way, I can't. ie something like this,
field_name='meats'
field = blt._meta.get_field(field_name)
field.add(bacon)
will throw "AttributeError: 'ManyToManyField' object has no attribute 'add'".
So, how can I use ._meta or a similar approach to get and refer to these fields in a way that will let me use .add()? (bonus round, how and why is "blt.meats" different than "blt._meta.get_field('meats')" anyway?)
Why do you want to do
field = blt._meta.get_field(field_name)
field.add(bacon)
instead of
blt.meats.add(bacon)
in the first place?
If what you want is to access the attribute meats on the blt instance of the Sandwich class because you have the string 'meats' somewhere, then it's plain python you're after:
field_string = 'meats'
meats_attribute = getattr(blt, field_string, None)
if meats_attribute is not None:
meats_attribute.add(bacon)
But if your at the point where you're doing that sort of thing you might want to revise your data modelling.
Bonus round:
Call type() on blt.meats and on blt._meta.get_field(field_name) and see what each returns.
One is a ManyToManyField, the other a RelatedManager. First is an abstraction that allows you to tell Django you have a M2M relation between 2 models, so it can create a through table for you, the other is an interface for you to query those related objects (you can call .filter(), .exclude() on it... like querysets): https://docs.djangoproject.com/en/4.1/ref/models/relations/#django.db.models.fields.related.RelatedManager
In my django admin I'm trying to show a field of my model which may has multiple values (like a list). Here's my definition of the field in models.py
related_countries = CountryField(
multiple=True,
blank=True
)
So when I create a model in the database, what I got as the value of the field is something like
AL,AS
Then for my admin page, I didn't put it in the list_display because I don't want it to be shown at the page where all the records of this models is printed. I want it to be shown only when I click one of the record and check the detail of this record. So when I'm at the page that shows everythhing, it works well.
Also, the record cannont be modified on the admin page so I have this function on my admin code:
def has_change_permission(self, request: HttpRequest, obj=None) -> bool:
return False
And there comes the issue: When I enter the page for the detail of the record, I got a TypeError at XXX unhashable type: 'list' and I'm pretty sure it comes from the field related_countries. Cause when I removed the function to make it possible to modify the record, anything works well cause there's a bloc for the related_countries to let me modify the countries. But when it becomes impossible to modify anything, it seems like the admin doesn't know how to present the list of the countries.
I tried to add this function but it didn't work:
def get_related_countries(self, obj):
return ",".join([c for c in obj.related_countries])
It doesn't work. I even tried to make it return an empty list but still not working. I guess the function is never called.
I'm not sure if I should add codes for serializers.py or views.py. It's empty for now.
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.
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([""])
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?