I want my model to get a GUID as key_name automatically and I'm using the code below. Is that a good approach to solve it? Does it have any drawbacks?
class SyncModel(polymodel.PolyModel):
def __init__(self, key_name=None, key=None, **kwargs):
super(SyncModel, self).__init__(key_name=str(uuid.uuid1()) if not key else None,key=key, **kwargs)
Overriding __init__ on a Model subclass is dangerous, because the constructor is used by the framework to reconstruct instances from the datastore, in addition to being used by user code. Unless you know exactly how the constructor is used to reconstruct existing entities - something which is an internal detail and may change in future - you should avoid overriding it.
Instead, define a factory method, like this:
class MyModel(db.Model):
#classmethod
def new(cls, **kwargs):
return cls(key_name=str(uuid.uuid4()), **kwargs)
There is an article by Nick about pre and post put hooks which and be used to set the key_name, I don't know if your current method is valid or not but at least you should be aware of other options.
Related
I try to figure out what is the best practice in Python inheritance principles, when there is a 'bad idea' to change method signature in a child.
Let's suppose we have some base class BaseClient with already implemented create method (and some abstract ones) that fits good for almost all 'descendants' except one:
class BaseClient(object):
def __init__(self, connection=None):
pass
def create(self, entity_id, data=None):
pass
class ClientA(BaseClient):
pass
class ClientB(BaseClient):
pass
The only class ClientC needs another implementation of create method with a little bit another method signature
class ClientC(BaseClient):
....
def create(self, data):
pass
So the question is how to make this in a more 'pythonic' way, taking into account best python practice? Of course we can use *args, **kwargs and other **kwargs-like approaches in parent (child) method, but I'm afraid it makes my code less readable (self-documented).
I'd say, just add the parameter back as keyword with default value None. Then raise an error that explains that some of the input data is lost.
class ClientC(BaseClient):
....
def create(self,entity_id=None, data):
if entity_id:
raise RedudantInformationError("Value for entity_id does nothing")
pass
This way whenever a programmer tries to handle child C like the other childs, he'll get a warning reminding him, which however he can easily by-step by using the try-Syntax.
The answer to "can I change signature of child methods?" is yes, nonetheless it is very bad practice.
The children function overriding the parents class must have the same signature, if you want to be SOLID and not violating the LSP.
The example above:
class BaseClient:
def create(self, entity_id, data=None):
pass
class EntityBasedClient(BaseClient):
def create(self, entity_id, data=None):
pass
class DataBasedClient(BaseClient):
def create(self, data):
pass
Is violating the principle and would also raise a linter warning ("Parameters differ from overridden 'create' method")
Also raising a RedudantInformationError, as proposed by #Sanitiy to keep the consistency of the signature, is still violating the principle, as the parent-method would have a different behaviour if used in place of the child-method.
Take a look also at:
Python Method overriding, does signature matter?
I am not sure there is a Pythonic way of doing this, as you can just do as you did in the question. Rather, I would say that this is more about OOP than being Pythonic matter.
So I assume that there are other methods implemented in BaseClient other than create that other children share (otherwise, no point is making ClientC a child of BaseClient). In your case, looks like ClientC is diverging from the rest by requiring a different signature of create method. Then maybe it is the case to consider splitting them?
For example you could have the root BaseClient implement all shared methods except create, and then have two more "base" children, like this:
class EntityBasedClient(BaseClient):
def create(self, entity_id, data=None):
pass
class DataBasedClient(BaseClient):
def create(self, data):
pass
So now you can inherit without violating any rule:
class ClientA(EntityBasedClient):
pass
class ClientB(EntityBasedClient):
pass
class ClientC(DataBasedClient):
pass
Also, if the create implementation of those two version are pretty similar, you could avoid the code duplication by having a more generic private method implemented in BaseClient with signature _create(self, entity_id=None, data=None), and then call it with appropriate arguments from inside the EntityBasedClient and DataBasedClient.
The point of my question is the following. I have Django form with a field, which inherits the Selet2 field:
class Select2ModelField(MyBaseSelect2ModelField, AutoModelSelect2Field):
'''
Select2ModelField, that uses ajax to get autocomplete options.
Should be used by default.
'''
widget = Select2ChoiceWidget
class LimitedDepartmentChoiceField(Select2ModelField):
def __init__(self, *args, **kwargs):
super(LimitedDepartmentChoiceField, self).__init__(*args, **kwargs)
And then I use it in my form, creating this field in a views.py, because the content of this field depends on the request data:
form = RepresentativeCreateEditForm(request.POST)
form.fields['department'] = LimitedDepartmentChoiceField(label=u'Department',
queryset=Department.objects.filter(
id__in=all_deps_ids))
The problem is that when two different users enter this page at the same time, they both have the same list of options, exactly the one which the user, who first load the page, has. And this behaviour is incorrect, they should have the different lists of options.
Please, could anyone tell me how I can solve this problem?
It sounds like a value is getting set as a class attribute (somewhere, on one of your classes), rather than as an attribute of a particular instance of a class. There's a lot of inheritance going on, so you might have to do some digging to see exactly where the problem is. My guess is that it's the Select2ChoiceWidget class.
From your code example it looks like all instances of Select2ModelField and its subclasses are sharing a single Select2ChoiceWidget class between themselves. I would think this would be the cause of the problem.
I don't know a whole lot about the Django classes you're using, but maybe try something along these lines?
class Select2ModelField(MyBaseSelect2ModelField, AutoModelSelect2Field):
'''
Select2ModelField, that uses ajax to get autocomplete options.
Should be used by default.
'''
def __init__(self, *args, **kwargs):
# Not sure if this is the proper way to instantiate this class,
# but doing so would help avoid leaking data across the instances
# of Select2ModelField and its subclasses.
self.widget = Select2ChoiceWidget()
# Do the parent class(es) for good measure.
super(Select2ModelField, self).__init__(self, *args, **kwargs)
In GAE's db.Model properties, we have a required parameter that disallows an entity of that model from being created without a value for that property.
e.g.:
class user(db.Model):
isFromUK = db.BoolProperty(required = True)
fromCounty = db.StringProperty()
How can I do essentially required = True on fromCounty iff the isFromUK == True?
I am aware this may not be possible directly in GAE implementation (I have not found a way in docs) - but I wondered if there may be some simple way to implement this, perhaps with a #ClassMethod?
I have not had cause to use one before, so I am not sure if that would offer a solution.
This is how you would override .put() to do your special validation before continuing with the regular (ie. super-class' .put):
class user(db.Model):
...
def put(self, *args, **kw):
if self.isFromUK:
if not self.fromCountry:
raise ValueError("Need fromCountry if isFromUK..")
super(user, self).put(*args, **kwargs)
What I'm trying to do is create a dynamic ModelForm that generates extra fields based on one of its class-attributes to use in a ModelAdmin. Something like:
class MyModelForm(forms.ModelForm):
config_fields = ('book_type', 'is_featured', 'current_price__is_sale')
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
In this case, MyModelForm would generate fields based on the config_fields attribute by performing some introspection. My approach so far looks something like this (based on this answer https://stackoverflow.com/a/6581949/677985):
class ConfigForm(type):
def __new__(cls, name, bases, attrs):
if 'config_fields' in attrs:
for config_field in attrs['config_fields']:
# ... (removed for clarity)
attrs.update(fields)
return type(name, bases, attrs)
class MyModelForm(forms.ModelForm):
__metaclass__ = ConfigForm
config_fields = ('book_type', 'is_featured', 'current_price__is_sale')
This approach works well enough, but I'm not quite happy with it for several reasons:
The validation doesn't seem to work, but this is a minor concern for now
I'm not quite sure why the "if config_field in attrs:"-condition is needed, but it is
I would prefer for MyModelForm to inherit instead of setting the __metaclass__ attribute, the base-class could then be easily reused and would allow me to easily override the clean- and __init__-methods.
I tried implementing the third item, the result being that the extra-fields did not show up in the admin-form. I'd be grateful if someone could help me figure this out, or at least point me in the right direction.
I am aware that using a metaclass for this probably overkill, and would guess that part of the problem is that ModelForm already has one or two metaclasses in its inheritance-chain. So if anyone has an alternate solution that accomplishes the same, that would make me just as happy.
I believe that the ModelForm already has a metaclass, but you're overwriting it by setting your own. That's why you're not getting validation or any of the other built in goodness of modelforms.
Instead, you should be able to use type directly to create your ModelForm, which will describe the type you want, but still cause the ModelForms metaclass to do its thing.
Example:
config_fields = ('book_type', 'is_featured', 'current_price__is_sale')
# the below is an example, you need more work to construct the proper attrs
attrs = dict((f, forms.SomeField) for f in config_fields)
ConfigModelForm = type('DynamicModelForm', (forms.ModelForm,), attrs)
class MyModelAdmin(admin.ModelAdmin):
form = ConfigModelForm
You can wrap the first part up in a function if need be, and invoke it for your form attribute in your ModelAdmin.
See my answer here for links and discussion on using type.
How about this,
Basically any form that extends your StepForm will also have the metaclass you wanted in the case below it's StepFormMetaclass, please note that if you have the form defined in some form.py file, you will need to import the form in the ___init___.py so that it will execute it during django starting sequence.
from django.forms.forms import DeclarativeFieldsMetaclass
class StepFormMetaclass(DeclarativeFieldsMetaclass):
.......
def __new__(meta_class, name, bases, attributes):
.....
return DeclarativeFieldsMetaclass.__new__(meta_class, name, bases, attributes)
class StepForm(six.with_metaclass(StepFormMetaclass, forms.Form, StepFormMixin)):
def __init__(self, *args, **kwargs):
super(StepForm, self).__init__(*args, **kwargs)
def as_p(self):
return ......
I am trying to write a base crud controller class that does the
following:
class BaseCrudController:
model = ""
field_validation = {}
template_dir = ""
#expose(self.template_dir)
def new(self, *args, **kwargs)
....
#validate(self.field_validation, error_handler=new)
#expose()
def post(self, *args, **kwargs):
...
My intent is to have my controllers extend this base class, set the
model, field_validation, and template locations, and am ready to go.
Unfortunately, decorators (to my understanding), are interpreted when
the function is defined. Hence it won't have access to instance's
value. Is there a way to pass in dynamic data or values from the sub
class?
For example:
class AddressController(BaseCrudController):
model = Address
template_dir = "addressbook.templates.addresses"
When I try to load AddressController, it says "self is not defined". I am assuming that the base class is evaluating the decorator before the sub class is initialized.
Thanks,
Steve
Perhaps using a factory to create the class would be better than subclassing:
def CrudControllerFactory(model, field_validation, template_dir):
class BaseCrudController:
#expose(template_dir)
def new(self, *args, **kwargs)
....
#validate(field_validation, error_handler=new)
#expose()
def post(self, *args, **kwargs):
....
return BaseCrudController
Unfortunately, decorators (to my
understanding), are interpreted when
the function is defined. Hence it
won't have access to instance's value.
Is there a way to pass in dynamic data
or values from the sub class?
The template needs to be called with the name of the relevant attribute; the wrapper can then get that attribute's value dynamically. For example:
import functools
def expose(attname=None):
if attname:
def makewrapper(f):
#functools.wraps(f)
def wrapper(self, *a, **k):
attvalue = getattr(self, attname, None)
...use attvalue as needed...
return wrapper
return makewrapper
else:
...same but without the getattr...
Note that the complication is only because, judging from the code snippets in your Q, you want to allow the expose decorator to be used both with and without an argument (you could move the if attname guard to live within wrapper, but then you'd uselessly repeat the check at each call -- the code within wrapper may also need to be pretty different in the two cases, I imagine -- so, shoehorning two different control flows into one wrapper may be even more complicated). BTW, this is a dubious design decision, IMHO. But, it's quite separate from your actual Q about "dynamic data".
The point is, by using the attribute name as the argument, you empower your decorator to fetch the value dynamically "just in time" when it's needed. Think of it as "an extra level of indirection", that well-known panacea for all difficulties in programming!-)