Django suppresses exceptions? - python

Been stuck with hard to find misbehavior. After many hours revealed it looks like Django suppresses AttributeError and possibly other exceptions:
from django import forms
class MyBaseForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('field1', 'field2', )
…
class MyForm(MyBaseForm):
def clean_field1(self):
super(MyForm, self).clean_field1() # calling non-exitsting method
# instead of AttributeError exception being raised,
# following code is not executed without a warning
return self.another_field_handler('field1')
Can anybody explain if this surprising behavior is normal for Django forms ? Some link where is it documented?

Related

Overloading changelist_view with no changes causing errors

Overloading changelist_view and calling the super() causes attribute errors.
I'm creating a super basic dashboard and I am overriding the changelist_view method of a ModelAdmin class. However, this override is resulting in an error "NoneType object has no attribute 'has_header'." However, I'm literally not doing anything but override the changelist_view and calling the super class - I haven't made any changes yet.
In admin.py
class SummaryAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
response = super().changelist_view(request, extra_context)
The corresponding model in models.py
class Summary(Failure):
class Meta:
proxy = True
verbose_name = 'Failure Summary'
verbose_name_plural = 'Failures Summary'
This is literally the entire contents of the admin model. When I try to go to the django admin panel, I get the attribute error. As far as I can tell, this should be no different than not overriding changelist_view at all, but if I delete the override everything functions as normal.
Update: I literally copied the changelist_view code from options.py rather than calling the super class and I do not get this error, so I suspect it has something to do with how I'm calling the super class.
The problem with the above code is it lacks a return statement. changelist_view returns a response, and an overload that does not return will cause all sorts of errors. This is an easy mistake to make if you're used to languages that will not let you compile if you forget your return or it does not match the stated type.

Alternative code position for Django admin list display settings

I am following the tutorial of Django 1.6, which includes a model Poll that has a derived attribute was_published_recently (a method of class Poll). The model was originally defined as follows.
# polls/models.py (excerpted)
class Poll(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
And the admin interface for this app:
# polls/admin.py (excerpted)
class PollAdmin(admin.ModelAdmin):
# ...
list_display = ('question', 'pub_date', 'was_published_recently')
admin.site.register(Poll, PollAdmin)
Now we want to improve the display and sorting functionality of was_published_recently.
In the tutorial, file polls/models.py is updated:
class Poll(models.Model):
# ...
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
However, I think this may not be good enough in practice, because what we are specifying is completely about the admin user interface, not the model per se. So I instead updated polls/admin.py:
class PollAdmin(admin.ModelAdmin):
Poll.was_published_recently.admin_order_field = 'pub_date'
Poll.was_published_recently.boolean = True
Poll.was_published_recently.short_description = 'Published recently?'
# ...
After this modification, the app works as expected as well (multiple polls work well also). Since I am new to Python, I investigated a bit further by printing was_published_recently in both Poll and PollAdmin:
class Poll(models.Model):
# ...
print("in class Poll", was_published_recently)
class PollAdmin(admin.ModelAdmin):
print("in class PollAdmin", Poll.was_published_recently)
# ...
And the output is
in class Poll <function Poll.was_published_recently at 0x10fc92050>
in class PollAdmin <function Poll.was_published_recently at 0x10fc92050>
So apparently was_published_recently in class Poll is the same as Poll.published_recently accessed in class PollAdmin.
My question: Should I specify the admin_order_field stuffs in admin.py or models.py? If specified in admin.py instead of models.py, are there any drawbacks?
Briefly, everything is working as intended, and it's semantically the same to put admin_order_field stuffs either in models.py or admin.py.
So apparently was_published_recently in class Poll is the same as Poll.published_recently accessed in class PollAdmin.
Yes. They should be the same. Classes are objects. So Poll is an object. Poll.was_published_recently is an attribute of object Poll, and is also an object with type instancemethod. Wherever you access it, it is the same object.
AFAIK, the only difference between writing admin_order_field stuffs in models.py and admin.py is the order of interpretation. Django loads models.py before admin.py, so everything runs at loading time and relies on admin_order_field stuffs will fail. But since admin_order_field is only used in admin.py, I think what you are doing is fine.
Python is so dynamic that allows you to modify definitions from even other modules. This can lead to hard-to-find bugs and bad readability / maintainability. Be sure to use this black magic with caution.

UserManager ignored in Django

Given this Django code in my models.py:
class ClientManager(UserManager):
def create_user(self, *args, **kwargs):
raise(Exception)
client = Super(UserManager, self).create_user(*args, **kwargs)
return client
class Client(AbstractUser):
objects = ClientManager()
How come no exception is raised when I create a Client user from the admin?
I've tried many variations on that principle, but no create_user ever seems to be used apart from the model's __init__(). Adding an exception in django.contrib.auth.models.UserManager.create_user() method also leads to the user being created without raising an exception, which seems to indicate that I'm missing something big, here.

PyCharm doesn't understand custom Manager of model

I extend default model manager and add cache-specific logic to it:
class ReadOnlyManager(manager.Manager):
use_for_related_fields = True
def create(self, **kwargs):
obj = super(ReadOnlyManager, self).create(**kwargs)
cache.cache_read_only_object(obj)
...
return obj
def update(self, *args, **kwargs):
raise ReadOnlyException()
def by_id(self, object_id):
return cache.retrieve_read_only_object(self.model, object_id)
def by_lookup(self, lookup_key, lookup_value):
return cache.retrieve_read_only_object_by_lookup(self.model, lookup_key, lookup_value)
Then I created abstract model that uses it:
class ReadOnlyModel(models.Model):
class Meta:
abstract = True
objects = ReadOnlyManager()
I use it in concrete model:
class TokenType(ReadOnlyModel):
code = models.CharField(_('code'), max_length=30, unique=True)
description = models.CharField(_('description'), max_length=100)
lookups = {
'code': 'code'
}
When I tried to call method specific for custom cache, for example *by_id*:
TokenType.objects.by_id(1) # This code works
PyCharm highlights it and writes "Unresolved attribute reference" warning. When I press CMD+Space after TokenType., I see, that autocomplete box contains two objects items: one marked with function icon and have type ReadOnlyManager, second - with method icon and have type Manager.
Is it PyCharm bug? How to enable autocomlete for additional methods in custom manager?
This seems to be a problem of PyCharm. Writing an auto completion for Python is really a hard task, especially for things like Django Models, which uses Meta Classes and other nasty stuff.
However it is possible to complete, and it seems not so difficult, for your example my autocompletion ( https://github.com/davidhalter/jedi/tree/dev, work in progress, don't use it yet) is able to complete it:
Completing TokenType.objects. :
update
by_id
by_lookup
create
use_for_related_fields
Completing TokenType.:
__metaclass__
__hash__
_get_next_or_previous_in_order
__ne__
date_error_message
description
_perform_date_checks
delete
clean
objects
unique_error_message
_set_pk_val
_deferred
save_base
pk
serializable_value
full_clean
__init__
code
save
__str__
validate_unique
clean_fields
__repr__
_perform_unique_checks
__reduce__
_get_unique_checks
prepare_database_save
_get_pk_val
__eq__
lookups
_get_next_or_previous_by_FIELD
Meta
_get_FIELD_display
As far as I'm concerned, PyCharm is Closed Source, so I think you'll have to talk to the PyCharm developers.

Why are form field __init__ methods being called on Django startup?

I have a Django app with custom form fields, some of which have slow operations in their constructors. I was surprised recently to find out that those constructors were getting called when Django itself was starting up, even before a user does something that requires that form in a view.
Why are they getting instantiated at server start?
Example:
urls.py:
from myapp.views import view1
...
url(r'^test$', view1.test),
views/view1.py:
class MyForm(ModelForm):
class Meta:
model = MyModel
field1 = MyChoiceField()
class MyChoiceField(ChoiceField):
def __init__(self, choices=(), required=True, widget=None, label=None,
initial=None, help_text=None, *args, **kwargs):
super(ChoiceField, self).__init__(required, widget, label, initial,
help_text, *args, **kwargs)
self.choices = [(m.id, m.name) for m in ReallyLargeTableModel.objects.all()]
If I set a break point inside that field constructor, then start up Django, it breaks the first time I request any page, even if the view in question does not need that form or field. The stacktrace leads back to the import line in urls.py.
Is this because I'm importing view1 in urls.py, instead of importing view1.test?
Edit: This isn't Django specific, here is a test case the illustrates the behavior:
class Something():
def __init__(self):
print "Something __init__() called"
class UsesSomething():
field = Something()
If you run this in the interactive terminal, it will print "Something init() called". This was surprising to me because I have not actually instantiated a UsesSomething object.
Because you instantiate the fields in the form definition, which is presumably being imported by one of your views.
The field init is the wrong place to do this sort of dynamic initialization, for this exact reason. You want something that is called when the form is initialized: ie, the form's __init__.
That said, you don't actually want to do this at all - you just need to use forms.ModelChoiceField, which takes a queryset and does the dynamic assignment of choices for you.
class MyForm(ModelForm):
field1 = forms.ModelChoiceField(queryset=ReallyLargeTableModel.objects.all())
In your example:
class UsesSomething():
field = Something()
The line of code field = Something() will execute when you import the containing module as Python processes the class definition. This is just how Python works. You can actually put arbitrary code inside a class definition.
module: test.py:
class UsesSomething():
print "wow!"
>>> import test
wow!

Categories

Resources