django subclass not calling superclass (derived from modelform) clean method - python

I have a django form (formA) that inherits from modelform.
In another app, I have a form that derives from that form (formB).
This all works ok, including obtaining fields from the base class formA, but when the clean method is called, it doesn't call the formA clean method. Instead it skips formA, and calls django's modelform.clean.
I can create a clean method in formB and this is called, but calling the super().clean() method also steps immediately into django's modelform.clean.
Why might this be happening and what do I have to do to get the correct inheritance chain for the clean method?
MTIA

It turned out that the different apps were in different venv prefixes, and this was why the inheritance wasn't working.
So, all fixed now.

Related

WTForms/Flask-WTF class attributes vs instance attributes

I'm now trying to use Flask-WTF (powered by WTForms) to render my frontend forms submission.
However, there is a limitation that all the fields in a Form object are class-level attributes, namely all instances of the class share the same fields.
When I tried to add multiple form instances and render them on the same page, it just doesn't work because the __init__ function in a Form subclass doesn't work, you cannot add fields or modify fields in the __init__ function, and all the instances are sort of "synchronized" after I clicked the submit button.
I'm essentially trying to make a single submit button that submits several forms, while this built-in functionality of Form object hinders the process. I'm now trying to modify the BaseForm class which is inherited by Form, and see if I can dig out something to work :(
I believe this has something to do with the Metaclass in WTForms, if anyone has encountered this problem please save me, and many thanks...

Should I prefer one general signal instead of multiple specific ones?

When the user creates a product, multiple actions have to be done in save() method before calling super(Product,self).save(*args,**kwargs).
I'm not sure if I should use just one pre_save signal to do all these actions or it is better to create a signal for each of these actions separately.
Simple example (I'm going to replace save overrides by signals):
class Product(..):
def save(...):
if not self.pk:
if not self.category:
self.category = Category.get_default()
if not self.brand:
self.brand = 'NA'
super(Product,self).save(*args,**kwargs)
...
SO
#receiver(pre_save,sender=Product)
def set_attrs(instance,**kwargs):
if kwargs['created']:
instance.category = Category.get_default()
instance.brand = 'NA'
OR
#receiver(pre_save,sender=Product)
def set_category(instance,**kwargs):
if kwargs['created']:
instance.category = Category.get_default()
#receiver(pre_save,sender=Product)
def set_brand(instance,**kwargs):
if kwargs['created']:
instance.brand = 'NA'
This is just simple example. In this case, the general set_attrs should be probably enough but there are more complex situations with different actions like creating userprofile for user and then userplan etc.
Is there some best practice advice for this? Your opinions?
To put the facts out simply, it could be pointed out as a single piece of advice,
If action on one model's instance affects another model, signals are the cleanest way to go about. This is an example where you can go with a signal, because you might want to avoid some_model.save() call from within the save() method of another_model, if you know what I mean.
To elaborate on an example, when overriding save() methods, common task is to create slugs from some fields in the model. If you are required to implement this process on multiple models, then using a pre_save signal would be a benefit, rather than hard-coding in save() method of each models.
Also, on bulk operations, these signals and methods are not necessarily called.
From the docs,
Overridden model methods are not called on bulk operations
Note that the delete() method for an object is not necessarily called when deleting objects in bulk using a QuerySet or as a result of a cascading delete. To ensure customized delete logic gets executed, you can use pre_delete and/or post_delete signals.
Unfortunately, there isn’t a workaround when creating or updating objects in bulk, since none of save(), pre_save, and post_save are called.
For more reference,
Django override save() or signals?
Overriding predefined model methods
Django: signal or model method?

How can I create a form instance outside of a view?

I'm currently writing a Flask app. One of my views has very complex business logic so I moved that to a class declared outside the view. In the constructor of that class I create several instances of flask_wtf.form.Form objects.
My problem is that at runtime I get the following error:
*** RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in a way. To solve
this set up an application context with app.app_context(). See the
documentation for more information.
(ipdb is mine)
I assume the form objects need to be in the view? But I want to move the work of creating them into a separate class so the view won't get too complex, otherwise it's unmanageable.
You can't. flask_wtf.Form requires the application context to set up CSRF.
It doesn't really make sense to instantiate a form outside of where it will be used, because you need to instantiate it with the data that is submitted to do anything useful.
Move creating the form instances to a method that you call on that class, rather than in it's __init__ method.

When are create and update called in djangorestframework serializer?

I'm currently implementing djangorestframework for my app RESTful API. After playing around with it, I still do not clearly understand what .create(self, validated_data) and .update(self, validated_data) used for in the serializer. As I understand, CRUD only calls the 4 main methods in viewsets.ModelViewSet: create(), retrive(), update(), and destroy().
I also have already tried to debug and print out stuff to see when the .create() and .update() methods are called in both ModelViewSet and ModelSerializer. Apparently, only the methods in ModelViewSet are called when I do the HTTP verbs. However, for ModelSerializer, I don't see any calls in those 2 methods. I just want to know what are those methods used for in ModelSerializer since I see that people override those methods a lot in the serializer.
You really must split things between the views and the serializer.
Serializers
The Serializer is a standalone object. It is used for converting a Django model (or any kind of python datastructure, actually) into a serialized form, and the other way around.
You may use it as such, wherever you want. It does not even need an actual HTTP request as long as you don't need URIs in your output.
The ModelSerializer subclass is a specialized kind of Serializer that adds "load-from-model" and "save-to-model" functionality.
The "save-to-model" entry point is the save() method. For easier overriding, its default implementation will delegate its work to either the create() or update() method of the serializer, depending on whether it is creating a new model instance, or updating one.
The purpose of that is customization: it gives you, the developer, the option to override just the create method, just the update method, or common behavior.
For instance, it allows you to do this kind of things:
def save(self, **kwargs):
# Will be done on every save
kwargs['last_changed'] = timezone.now()
return super().save(**kwargs)
def create(self, instance, data):
# Will only be done if a new object is being created
data['initial_creation'] = timezone.now()
return super().create(instance, data)
That's a basic example. There, the last_changed field will be set every time an object is saved, be it a creation or an update.
As a sidenote, you probably do not want to do that. Things such as setting "last_changed" fields should live in the view, not in the serializer.
Viewsets
In a completely different place, Django REST framework supplies Viewsets. Those are an organized collection of views, revolving around implementing a CRUD API for a model.
As such, it structures it functionality into a set of methods, namely create(), retrieve()/list(), update() and delete().
The main point being: there is no connection whatsoever between the viewset's create() method and the serializer's create() method.
It just happens that the default implementation of the viewset's methods uses a ModelSerializer and that the default implementation of that serializer's save() method delegates the job to methods that have the same name.
By the way, about the last_changed example, here is how you would do it in the view:
def perform_create(self, serializer):
now = timezone.now()
serializer.save(initial_creation=now, last_changed=now)
def perform_update(self, serializer):
serializer.save(last_changed=timezone.now())
That's functionally equivalent to the example above, but lives in the viewset.
Conclusion
So back to your question, the specific thing you should override depends on which object is responsible for the task you want to add.
If your custom behavior is part of the serialization process, that is, the process of converting raw data back into a proper Django model and saving it, then you should override the Serializer's methods.
If, on the other hand, your custom behavior is specific to your viewset, then you should override the Viewset's methods.
As a hint, you may ask yourself the following question: if I use the same serializer in another place (maybe another viewset), should it always display that behavior?
I finally understand how the .create() and .update() work in Serializer (especially ModelSerializer) and how they are connected to Viewsets (especially ModelViewSet). I just want clarify the concept more clearly if someone comes to this question.
Basically, the 4 methods CRUD in ModelViewSet: .create(), .retrieve(), .update(), and .destroy() will handle the calls from HTTP verbs. By default, the .create() and .update() from ModelViewSet will call the .create() and .update() from ModelSerializer by calling the .save() method from the BaseSerializer class.
The save() method will then determine whether it will call .create() or .update() in ModelSerializer by determining whether the object self.instance exists or not.
In the rest-api design create, read, update and delete is a standard.
There is not quite big difference in create and update.
Please refer to this and
see create() method will create an item.
and
update() method need to specify which item to be updated.

In Django, ok to set Model.objects to another manager outside of model definition?

Suppose, in Django 1.6, you have the following model code:
class FooManager(models.Manager):
def get_queryset():
return ... # i.e. return a custom queryset
class Foo(models.Model):
foo_manager = FooManager()
If, outside the Foo model definition (e.g. in view code or in the shell), you do:
Foo.objects = FooManager()
Foo.objects.all()
you'll get an exception in the Django internal code on Foo.objects.all() due to a variable named lookup_model being `None'.
However, if you instead do:
Foo.objects = Foo.foo_manager
Foo.objects.all()
The Foo.objects.all() will work as expected, i.e. as if objects had been defined to be FooManager() in the model definition in the first place.
I believe this behavior is due to Django working its "magic" in creating managers during model definition (just as it works magic in creating model fields).
My question: is there any reason NOT to assign objects to an alternate manager in this way outside of the model definition? It seems to work fine, but I don't fully understand the internals so want to make sure.
In case you are wondering, the context is that I have a large code base with many typical references to objects. I want to have this code base work on different databases dynamically, i.e. based on a request URL parameter. My plan is to use middleware that sets objects for all relevant models to managers that point to the appropriate database. The rest of the app code would then go on its merry way, using objects without ever having to know anything has changed.
The trouble is that this is not at all thread safe. Doing this will change the definition for all requests being served by that process, until something else changes it again. That is very likely to have all sorts of unexpected effects.

Categories