I want to make my custom field extend from django foreign key.
class CustomField(models.ForeignKey):
def __init__(self, *args, **kwargs):
self.type=kwargs.pop('type', None)
super(CustomField, self).__init__(*args, **kwargs)
I am using like
CustomField('User', type="test")
This works correctly but i want to hard code model name in my field like this
super(CustomField, self).__init__('User', *args, **kwargs)
so that i can use
CustomField(type="test")
but then i get this error
__init__() got multiple values for keyword argument 'to'
The problem is that your are sending the to parameter used by models.ForeginKey in self and in the 'User' parameter when you make call super(CustomField, self).__init__('User', *args, **kwargs). You can try to do in this way:
class CustomField(models.ForeignKey):
def __init__(self, *args, **kwargs):
kwargs['to'] = 'User'
self.type = kwargs.pop('type', None)
super(CustomField, self).__init__(*args, **kwargs)
Related
I want to get <Model> value from a URL, and use it as an __init__ parameter in my class.
urls.py
url(r'^(?P<Model>\w+)/foo/$', views.foo.as_view(), name='foo_class'),
views.py
class foo(CreateView):
def __init__(self, **kwargs):
text = kwargs['Model'] # This is not working
text = kwargs.get('Model') # Neither this
Bar(text)
...
Clearly, I'm missing something, or my understanding of URL <> class view is wrong.
You should override dispatch method for such use cases.
class Foo(CreateView):
def dispatch(self, request, *args, **kwargs):
# do something extra here ...
return super(Foo, self).dispatch(request, *args, **kwargs)
For your specific scenario, however, you can directly access self.kwargs as generic views automatically assign them as an instance variable on the view instance.
I am trying to make a generic mixin for model fields (as opposed to form fields), the init for the mixin takes named arguments. I am running into trouble instantiating the mixin with another class.
Here is the code
class MyMixin(object):
def __init__(self, new_arg=None, *args, **kwargs):
super(MyMixin, self).__init__(*args, **kwargs)
print self.__class__, new_arg
class MyMixinCharField(MyMixin, models.CharField):
pass
...
class MyMixinModelTest(models.Model):
myfield = MyMixinCharField(max_length=512,new_arg="myarg")
Making the migration for this model produces the following output:
<class 'myapp.mixintest.fields.MyMixinCharField'> myarg
<class 'myapp.mixintest.fields.MyMixinCharField'> None
<class 'myapp.mixintest.fields.MyMixinCharField'> None
Migrations for 'mixintest':
0001_initial.py:
- Create model MyMixinModelTest
First, why is init running 3 times? Where does the kwarg 'new_arg' in the second two?
How do I create a field mixin for django?
EDIT:
As opposed to another question, this question asks about field mixins, the linked question refers to model mixins.
First, why is init running 3 times?
Although the models.py is only imported once, the Field objects created therein, such as...
myfield = MyMixinCharField(max_length=512, new_arg="myarg")
...are cloned several times, which involves calling the field constructor using the keyword args they were originally created with. You can use the traceback module to see where it's happening...
import traceback
class MyMixin(object):
def __init__(self, new_arg=None, *args, **kwargs):
super(MyMixin, self).__init__(*args, **kwargs)
print self.__class__, new_arg
traceback.print_stack()
...which shows the following several times in the output...
File "django/db/migrations/state.py", line 393, in from_model
fields.append((name, field.clone()))
File "django/db/models/fields/__init__.py", line 464, in clone
return self.__class__(*args, **kwargs)
File "myproj/myapp/models.py", line 11, in __init__
traceback.print_stack()
Where is the kwarg 'new_arg' in the second two?
When you originally called...
myfield = MyMixinCharField(max_length=512, new_arg="myarg")
..."myarg" is being passed in as the new_arg parameter to...
def __init__(self, new_arg=None, *args, **kwargs):
...but because you don't pass that parameter to the underlying Field constructor...
super(MyMixin, self).__init__(*args, **kwargs)
...it's not stored anywhere in the underlying Field object, so when the field is cloned, the new_arg parameter isn't passed to the constructor.
However, passing that option to the superclass constructor won't work, because the CharField doesn't support that keyword arg, so you'll get...
File "myproj/myapp/models.py", line 29, in MyMixinModelTest
myfield = MyMixinCharField(max_length=512, new_arg="myarg")
File "myproj/myapp/models.py", line 25, in __init__
super(MyMixinCharField, self).__init__(*args, **kwargs)
File "django/db/models/fields/__init__.py", line 1072, in __init__
super(CharField, self).__init__(*args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'new_arg'
How do I create a field mixin for django?
Because of this cloning behavior, if you want to add custom field options, you have to define a custom deconstruct() method so that Django can serialize your new option...
class MyMixin(object):
def __init__(self, new_arg=None, *args, **kwargs):
super(MyMixin, self).__init__(*args, **kwargs)
self.new_arg = new_arg
print self.__class__, new_arg
def deconstruct(self):
name, path, args, kwargs = super(MyMixin, self).deconstruct()
kwargs['new_arg'] = self.new_arg
return name, path, args, kwargs
class MyMixinCharField(MyMixin, models.CharField):
pass
class MyMixinModelTest(models.Model):
myfield = MyMixinCharField(max_length=512, new_arg="myarg")
...which outputs...
<class 'myapp.models.MyMixinCharField'> myarg
<class 'myapp.models.MyMixinCharField'> myarg
<class 'myapp.models.MyMixinCharField'> myarg
So I figured it out after lots of tinkering and re-reading the django docs on custom model fields
You need a deconstructor along with your init. Django fields need a deconstruct method to serialize.
The mixin should have this method as well:
class MyMixin(object):
def __init__(self, new_arg=None, *args, **kwargs):
self.new_arg = new_arg
super(MyMixin, self).__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super(MyMixin, self).deconstruct()
if self.new_arg is not None:
kwargs['new_arg'] = self.new_arg
return name, path, args, kwargs
Here is my form:
class RecipeForm(forms.Form):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(RecipeForm, self).__init__(*args, **kwargs)
Recipebase_id = forms.ModelChoiceField(queryset=Recipebase.objects.filter(user = self.user))
title = forms.CharField(max_length=500)
instructions = forms.CharField(max_length=500)
I want to filter model choice field based on user as you can see from the filter. But it gives the following error:
name 'self' is not defined
Any suggestions would be highly appreciated.
The self. would work only for objects created from a class. In this case you are not creating one, so it would not work as you would expect.
Instead, you need to override the queryset in the __init__ like this:
class RecipeForm(forms.Form):
Recipebase_id = forms.ModelChoiceField(queryset=Recipebase.objects.none())
def __init__(self, *args, **kwargs):
user = kwargs.pop('user') #Throws an error if user is not present
super(RecipeForm, self).__init__(*args, **kwargs)
qs = Recipebase.objects.filter(user=user)
self.fields['Recipebase_id'].queryset = qs
Another way to achieve the same is to make user a required argument in the form
class RecipeForm(forms.Form):
Recipebase_id = forms.ModelChoiceField(queryset=Recipebase.objects.none())
def __init__(self, user, *args, **kwargs):
super(RecipeForm, self).__init__(*args, **kwargs)
qs = Recipebase.objects.filter(user=user)
self.fields['Recipebase_id'].queryset = qs
And the view code would look like this:
form = RecipeForm(request.POST, user=request.user) #user would be passed in as a kwarg to the form class.
Putting your code starting at "Recipebase_id" at the indentation level you have it causes python to execute it at the time the file is parsed/imported. Self is passed into a method when the class is instantiated and the instance method is called, so at parse time self does not exist.
It's unclear to me if you want the Recipebase_id, title and instructions set in the init method. If you do, indent them to the same level as the lines above it. If not, then you'll need to get the value of user from somewhere other than self.
This question is about Python inheritance but is explained with a Django example, this should't hurt though.
I have this Django model, with Page and RichText models as well:
class Gallery(Page, RichText):
def save(self, *args, **kwargs):
# lot of code to unzip, check and create image instances.
return "something"
I'm only interested in using the save method in another class.
A solution could be:
class MyGallery(models.Model):
def save(self, *args, **kwargs):
# here goes the code duplicated from Gallery, the same.
return "something"
I'd like to avoid the code duplication and also I'm not interested in inheriting members from Page and RichText (so I don't want to do class MyGallery(Gallery):. If it would be legal I'd write something like this:
class MyGallery(models.Model):
# custom fields specific for MyGallery
# name = models.CharField(max_length=50)
# etc
def save(self, *args, **kwargs):
return Gallery.save(self, *args, **kwargs)
But it won't work because the save() in Gallery expects an instance of Gallery, not MyGallery.
Any way to "detach" the save() method from Gallery and use it in MyGallery as it were defined there?
EDIT:
I forgot to say that Gallery is given and can't be changed.
You can access the __func__ attribute of the save method:
class Gallery(object):
def save(self, *args, **kwargs):
return self, args, kwargs
class MyGallery(object):
def save(self, *args, **kwargs):
return Gallery.save.__func__(self, *args, **kwargs)
# or
# save = Gallery.save.__func__
mg = MyGallery()
print mg.save('arg', kwarg='kwarg')
# (<__main__.MyGallery object at 0x04DAD070>, ('arg',), {'kwarg': 'kwarg'})
but you're better off refactoring if possible:
class SaveMixin(object):
def save(self, *args, **kwargs):
return self, args, kwargs
class Gallery(SaveMixin, object):
pass
class MyGallery(SaveMixin, object):
pass
or
def gallery_save(self, *args, **kwargs):
return self, args, kwargs
class Gallery(object):
save = gallery_save
class MyGallery(object):
save = gallery_save
I'm not sure why you are against inheritance, particularly with regard to methods. I regularly create a MixIn class that is inherited by all of my Django models.Model, and it contains all manner of useful methods for URL creation, dumps, etc., etc. I do make the methods defensive in that they use hasattr() to make sure they apply to a particular class, but doing this is a real time saver.
I guess this is another simple question on django forms that I am struggling to find an answer for.
Say I have the following
class Form1(forms.Form):
a=forms.CharField( label=_("A"),max_length=40)
b=forms.CharField( label=_("B"),max_length=40)
class Form2(forms.Form):
c=forms.CharField( label=_("C"),max_length=40)
d=forms.CharField( label=_("D"),max_length=40)
class Form3(Form1,Form2):
def __init__(self, *args, **kw):
Form1.__init__(self,*args, **kw)
Form2.__init__(self,*args, **kw)
#Here I don't want to have a from Form1
# how can I exclude it so that validation does not bark??
I tried exclude=(a,) in Meta class defined in Form3 but does not work, form validation keeps failing form me.
Thanks in advance
Have you tried:
def __init__(self, *args, **kwargs):
super(Form3, self).__init__(*args, **kwargs)
del self.fields['a']
You can override the field and set it to None
class Form3(Form1,Form2):
a = None
Below is the reference:
https://code.djangoproject.com/ticket/8620#no1