Django model, default records - python

I am a beginner in Django, and I am learning models for now.
I have two tables in the backend, one a child of another (1-to-many relationship).
So far, so good.
What I want to do is set Django, so that if a record is created in the parent table, the child table will automatically create 3 records.
How do I program this?
Thanks.

You may be interested in something like this:
# ... other imports ...
from django.db.models.signals import post_save, pre_save
class Parent(models.Model)
# this decorator & this method go inside your model
#staticmethod
def create_children(sender, instance=None, **kwargs):
for x in range(3):
# I'm assuming you want the child to be linked to the parent immediately.
# You can set any other attributes you want here too, of course.
child = Child(parent = instance)
child.save()
pre_save.connect(Parent.create_children, Parent)
Note that in the pre_save.connect() call, you can call any [SomeClass].[SomeMethodOfThatClass] (this is the first argument) on the save of some other class (this is the second argument). In practice, though, I don't think I've actually ever done that, and I'm not sure that you need to do that here.

Related

Django - How to dynamically create signals inside model Mixin

I'm working on a model Mixin which needs to dynamically set signals based on one attribute.
It's more complicated but for simplicity, let's say the Mixin has this attribute:
models = ['app.model1','app.model2']
This attribute is defined in model which extends this mixin.
How can I register signals dynamically?
I tried to create a classmethod:
#classmethod
def set_signals(cls):
def status_sig(sender, instance, created, *args, **kwargs):
print('SIGNAL')
... do som things
for m in cls.get_target_models():
post_save.connect(status_sig,m)
My idea was to call this method somewhere in class automatically (for example __call__ method) but for now, I just tried to call it and then save the model to see if it works but it didn't.
from django.db.models.signals import post_save
print(post_save.receivers)
Realestate.set_signals()
print(post_save.receivers)
r = Realestate.objects.first()
r.status = 1
r.save()
output
[]
[((139967044372680, 46800232), <weakref at 0x7f4c9d702408; dead>), ((139967044372680, 46793464), <weakref at 0x7f4c9d702408; dead>)]
So you see that it registered those models but no signal has been triggered after saving the realestate.
Do you know how to make it work? Even better without having to call method explicitely?
EDIT:
I can't just put the signals creation inside mixin file because models depends on the string in child model.
If you haven't already solved this:
In the connect method, set weak=False. By default it's True so the locally-defined function reference will get lost if the object instance is garbage collected.
This is likely what's happening to your status_sig function; as you can see in the print out of the post_save receivers, the weakref's are dead so will always just return None
In the Django docs:
weak – Django stores signal handlers as weak references by default. Thus, if your receiver is a local function, it may be garbage collected. To prevent this, pass weak=False when you call the signal’s connect() method.
For more info on weakrefs, see Python docs

Should I be using controllers.py or #staticmethod in Django?

The person on our team who initially taught us django (and has subsequently left) utilized a controllers.py file for helper functions. A lot of these functions are directly related to classes. I prefer to use #staticmethod to house these helpers with the classes they're related to. For example, rather than doing this:
# controllers.py
def process_entry():
# do some exciting stuff that might not have to do with an instance
Called like this:
from myapp.controllers import process_entry
process_entry()
I'd prefer this:
# models.py
class Entry(models.Model):
name = CharField...
# some other fields
#staticmethod
def process_entry():
# do some exciting stuff that might not have to do with an instance
Called like so:
from myapp.models import Entry
Entry.process_entry()
Is there a preferred, standard way to deal with situations like this or is it just personal preference? Does anyone else utilize a controllers.py file? What goes in there?
Thanks.
EDIT:
Possibly a better example, commissions.
# models.py
class Commission(models.Model):
check = ForeignKey
payment = ForeignKey
# other fields
class Check(models.Model):
# fields
class Payment(models.Model):
# fields
Any time a Check or Payment instance is modified an adjustment as to be made to any related Commission instances or any time someone wants to manually run commissions, they can do so. So where should run_commissions() go? I prefer this, but apparently this shouldn't be encapsulated in a data-related model?
# models.py
class Commission(models.Model):
check = ForeignKey
payment = ForeignKey
# other fields
#staticmethod
def run_commissions():
# do stuff
Static methods are used for grouping related functions in one class (mostly for factory methods), beside that, there is no difference between static method and function.
BUT. In your example you are assigning behavior to DATABASE model. DATABASE models are not LOGIC models, and you should separate them from your app logic. Anyway, controllers is also a bad name in that matter.
I'm not sure what process_entry does, but if it's only changing one Entry entity, then it can be named: Entry.process(), but NOT Entry as DB model! just another Entry class. However if that function does more than just changing Entry, then it shouldn't be assigned to Entry entity, but made as a service function.

Change a django form class before it is instantiated

I'm wondering if it's possible to alter or change a form class before it's instantiated.
As a concrete example, I have a payment form which needs to be modified based on the payment system being used.
Ideally I'd rather not create different form classes and then choose different ones based on the payment system; instead the payment system object will "tell" the form class what changes it need to make -- for example, making certain fields optional or instructing them to use different widgets.
Is this possible? The alternative is to pass an object representing the payment system into the form, and then having it modify the form after instantiation, but that just seems clumsy somehow to have it run in the form class rather than the view. I feel like the Django "view" is closer to a controller, and it seems like this is where something like this should happen. I also feel like modifying it'd be better to modify the form_class object rather than the form instance; I'm not even sure if when you add fields after the fact like this it will handle validation and form fill-in correctly. Will it?
Anywhere, here's some sample code of how it would work passing the payment object into a form instantiation call:
payment_system.py:
class ExamplePaymentSystem(BasePaymentSystem):
def modify_form(self, form):
for fld in self.optional_fields:
form.fields[fld].required = False
…etc…
forms.py:
class ModifiablePaymentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.payment_system = kwargs.pop("payment_system", None)
super(ModifiablePaymentSystem, self).__init__(*args, **kwargs)
self.payment_system.modify_form(self)
You should not modify global static data (classes defined at module scope are static), because if you run your code in many threads per process (which is often done) one thread may modify form class used by the other threads.
If you your payment systems are static (you do not add new on the fly, while server is running) I'd define one form per payment system.
If not, you can always, define new form types on the fly like that:
def get_form_type(payment_system):
class DynamicForm(BasePaymentForm):
... add change fields etc...
return DynamicForm
or modify instances like that:
class PaymentForm(BasePaymentForm):
def __init__(self, ..., payment_system):
self.fields['foo'].required = False # <--- I'm writing code
#from the memory, so possibly you'll need t edit it
#but this is doable and easy to do.
How to remove field in forms (per OP request).
When you subclass:
This is hard and I think you'll need to browse through form internals and modify them by hand after subclass creation. This is a wild guess...
def get_form_type(payment_system):
class DynamicForm(BasePaymentForm):
... add change fields etc...
del DynamicForm.base_fields['foo']
return DynamicForm
When you modify instance:
I'm not 100% sure, but I peeked into django source code (unfortunately these details are not in docs). But i guess that you should:
class PaymentForm(BasePaymentForm):
def __init__(self, ..., payment_system):
del self.fields['foo']
The fields are a dict (or I guess -- OrderedDict for that matter) and to delete field you need to remove whole key-vaule mapping.

Django: Easily add extra manager for child class, still use default manager from AbstractBase

This question is about the last example on Custom managers and model inheritance.
I want to be able to do something similar to the following:
class ExtraManagerModel(models.Model):
# OtherManager class supplied by argument shall be set as manager here
class Meta:
abstract = True
class ChildC(AbstractBase, ExtraManagerModel(OtherManager)): # That doesn't work, something like that
...
# Default manager is CustomManager, but OtherManager is
# also available via the "extra_manager" attribute.
The whole purpose of this is that I don't want to write an ExtraManagerModel class for every overwritten manager in order to keep the default manager of the parent class (AbstractBase).
Any ideas how this can be acheived?
I am absolutely not sure that I understand your question. Your code snippet seems to be contradicting the comment underneath it.
Your code snippet looks like you want to be able to have different ExtraManagerModel classes. If that is the case, you can use an abstract class that is implemented by those ExtraManagerModels, and you inherit the abstract parent of those classes for the childC class.
Hope this helps.

Django - how do I _not_ dispatch a signal?

I wrote some smart generic counters and managers for my models (to avoid select count queries etc.). Therefore I got some heavy logic going on for post_save.
I would like to prevent handling the signal when there's no need to.
I guess the perfect interface would be:
instance.save(dispatch_signal=False)
How can I accomplish this?
Update
More information about what I'm doing, if anyone's interested:
Generic counters are stored in a separate table
Every time Django paginates an object list, it calls overriden count() method of my custom manager, which basically retrieves the static counter value for appropriate object class.
Signals trigger the logic of counters update, which is a bit complicated since it checks many aspects of related models (i.e. it has to generate a visibility property based on a nested category tree). I can't put this logic in Model.save() because one counter depends on many different models. I'd like to have that logic in one piece, instead of fragments spread around.
I am denormalizing some of my models, so I rewrite (duplicate) certain values across tables.
For testing purposes I run my little command-extension -- Dilla, to populate random data around.
I've noticed unwanted signals triggering, therefore I'd like them to run conditionally.
Hope it's clear enough. Excuse my language mistakes.
I found simple and easy solution:
MyModel.objects.filter(pk=instance.id).update(**data)
It is due to (https://docs.djangoproject.com/en/1.5/ref/models/querysets/#update):
Finally, realize that update() does an update at the SQL level and,
thus, does not call any save() methods on your models, nor does it
emit the pre_save or post_save signals (which are a consequence of
calling Model.save()).
You can disconnect and reconnect the signal. Try using a with: statement with this utility class:
class SignalBlocker(object):
def __init__(self, signal, receiver, **kwargs):
self.signal = signal
self.receiver = receiver
self.kwargs = kwargs
def __enter__(self, *args, **kwargs):
self.signal.disconnect(self.receiver)
def __exit__(self, *args, **kwargs):
self.signal.connect(self.receiver, **self.kwargs)
You can now use:
with SignalBlocker(post_save, my_post_save_handler):
instance.save()
A quick and dirty solution would be:
from django.db.models.signals import post_save
from somewhere_in_my_app import my_post_save_handler
post_save.disconnect(my_post_save_handler)
instance.save()
post_save.connect(my_post_save_handler)
But otherwise i strongly recommend moving your logic into the save() method of your model.
You can also call instance.save_base(raw=True) and check for the raw argument in your pre_save or post_save signal handler:
def my_post_save_handler(instance, raw, **kwargs):
if not raw:
heavy_logic()
You can add some sugar and get your perfect interface:
class MyModel:
def save(self, dispatch_signal=True, **kwargs):
self.save_base(raw=not dispatch_signal, **kwargs)
Note that save_base() is not part of the public API of Django, so it might change in a future version.

Categories