exchangelib consistently returns 'QuerySet' object has no attribute 'iterator' when using chunkify - exchangelib

Problem:
When using exchangelib for large amounts of emails(in this case 10K+) the entire set is attempted to be loaded. I have tried to employ chunkify:
from exchangelib import Credentials, Account
for item in account.inbox\
.filter(is_read=False, sender__contains='gmail')\
.only('is_read', 'subject', 'body') \
.order_by('-datetime_received')\
.iterator():
print('Email subject is:', item.subject)
print('Email is from:', item.sender)
Which yields the following log error:
for item in account.inbox.filter(is_read=False, sender__contains='gmail').only('is_read', 'subject', 'body').order_by('-datetime_received').iterator():
AttributeError: 'QuerySet' object has no attribute 'iterator'

The .iterator() method was deprecated in exchangelib v4.0.0 and finally removed in v4.7.0. exchangelib no longer does any internal caching so the method is a no-op.

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.

How to use Django's APIRequestFactory with an array of objects?

I have the following test
def test_bulk_post(my_faker,factory):
snippets = [{'code':'print(True)'},{'code':'print(True)'},{'code':'print(True)'}]
assert factory.post('/snippets/',snippets) == True
I am trying to extend the snippets app in the tutorial to accept multiple code objects in a single post request.
Right now this gives me:
/venv/lib/python3.8/site-packages/django/test/client.py(244)encode_multipart()
*** AttributeError: 'list' object has no attribute 'items'
so its not expecting a list.. But I want to give it one. How do I do that?
factory.post by default expects a key, value pairs that goes with multipart/form-data and not list hence error
You should probably set content_type='application/json' to pass data as JSON body
factory.post('/snippets/',snippets, content_type='application/json )

TypeError: expected string or bytes-like object User.id

I'm trying to register an new Transaction object on the DB using Django, but I'm having TypeError: expected string or bytes-like object when I try to do user_id = user.id I can't really understand why this is happening, since I do the same steps when registering a new Bank object (as shown on prints below). I've tried to debug and the local variables have the correct value, I've also tried to cast user.id with string or int, but none of them worked.
traceback console error create Transaction method create Bank method
models.py
Firstly, please don't post code or errors as images; they are text, they should be posted as text in the question.
However I don't see anything in any of those snippets that suggest the error is with the user - that line is probably highlighted because it's the last in that multi-line call.
Rather, the error looks to be in the reference to date.today - if that's the datetime.date class, then today is a method, which you would need to call:
Transaction.objects.create(date=date.today(), ... )
Or, since that field has a default anyway, you could leave out the date attribute from the create call altogether.

Getting "AttributeError: 'str' object has no attribute 'regex'" in Django urls.reverse

As in the title, I'm getting
AttributeError: 'str' object has no attribute 'regex'
I've seen many valid answers to this, but none of them applied to my code as they identified issues in the urls.py file. My issue is in the views.py file.
I get the exception when using reverse to generate a redirect URL:
HttpResponseRedirect(reverse('changetracker:detail', args))
When I use 'changetracker:detail' in other functions, I don't get the exception.
I'm answering this to share knowledge as I didn't see this particular root cause identified already.
The problem turned out to be that I should be using a keyword argument 'args=args' to pass in URL arguments, not a positional argument:
HttpResponseRedirect(reverse('changetracker:detail', args=args))
Using the positional argument (position 2) caused reverse to use that argument as the URL list and thus raise the AttributeError.

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