Overloading changelist_view with no changes causing errors - python

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.

Related

Django call a Model method inside another method of the same Model (in models.py)?

SOLVED BY JUST RESTARTING THE SERVER (python manage.py runserver)
I want to call a model method inside another model method in models.py but i receive the error AttributeError: module 'my_website.models' has no attribute 'my_model_method'
Here is my model:
class SaleCode(models.Model):
#my fields and methods...
#the method I want to call
def generate_token(self, apply=True, length=5):
# stuff
return {
"token": token,
"self-applyed": apply
}
#save() method override
def save(self, *args, **kwargs):
if not self.pk:
#self.code is one of my fields
self.code = self.generate_token()["token"] #the line that generates the error
super(SaleCode, self).save(*args, **kwargs)
What I have tried:
(As I read somewhere) I tried to place #classmethod (and #staticmethod) over the generate_token(...) declaration and then to call it as SaleCode.generate_token():
#classmethod
def generate_token(self, apply=True, length=5):
...
self.code = SaleCode.generate_token()["token"] #the line that generates the error
I wrote the function outside the method and then called it as a normal function (it worked but it does not seem to be a "clear" way to do that.)
I really don't know why but...
I just restarted the server and it worked.. really weird but know it works.

Django Rest Framework permission_classes not working

I have a problem using Django Rest Framework's permission_classes attribute.
The view I want to protect is defined as:
class Test(APIView):
permission_classes = [IsLoggedIn]
def get(self, request):
return Response("aaa")
I have also tried having the class inherit GenericAPIVIew.
permissions.py
from rest_framework import permissions
class IsLoggedIn(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return False
I'm trying to get the permission to at least always refuse the request, but it seems that the has_object_permission method is never getting called.
You have to override the has_permission(...) method instead of has_object_permission(...)
class IsLoggedIn(permissions.BasePermission):
def has_permission(self, request, view):
return False
I found this in drf offical document:
Limitations of object level permissions
For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.
Often when you're using object level permissions you'll also want to filter the queryset appropriately, to ensure that users only have visibility onto instances that they are permitted to view.
Because the get_object() method is not called, object level permissions from the has_object_permission() method are not applied when creating objects. In order to restrict object creation you need to implement the permission check either in your Serializer class or override the perform_create() method of your ViewSet class.

django-haystack - accessing request.GET from subclassed FacetedSearchView class

I have subclassed django-haystack's FacetedSearchView, and want to have an action take place when a specific GET parameter is present in the view's URL. I know exactly how to do this if I had a function-based view, but am at a complete loss when using a subclass of a subclass.
The request variable should be available somehow. I assume I need to call it up from some kind of super() call, maybe in an __init__() override? I've tried the following:
def __init__(self, *args, **kwargs):
super(MySearch, self).__init__(*args, **kwargs)
if self.request.GET.get("date_facet", ""):
do_something()
But it tells me that the returned request object is None, though by the URL it clearly shouldn't be.
Any thoughts?
Turns out, the request variable is accessible, it just has to be through self, which means you can only access it through a function common to the parent class. __init__ wasn't working, because request isn't defined until later in the parent class. To get things to work I ended up overwriting the get_results() class (originally just return self.form.search()), in a way similar to the following:
class Foo(ParentClass):
def get_results(self):
if 'date_facet' in self.request.GET:
year = int(self.request.GET['date_facet'])
return self.form.search().filter(some_filter_function)
return self.form.search()

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