I am using python 2.7 and confused about inheritance concept.
I want to make a script that can download from various manga (japanese comic site)
Every manga site uses a different method to save their file. So i have a "Manga_site" class and class called "mangacanblog" (this is a website manga).
Every manga site has a: homepage,collection,page,etc. and it's all different for each site. my question is. is this script correct to store those homepage,collection_page,etc variable? or should I use self.homepage in mangacanblog class and not in the Manga_site class?
class Manga_site:
def __init__(self,homepage,collection_page,base_manga_page,manga_title = ""):
self.homepage = homepage
self.collection_page = collection_page
self.base_manga_page = base_manga_page
self.manga_title = manga_title
class Mangacanblog(Manga_site):
def __init__(self,manga_title):
homepage = bloglink
collection_page = collectionpagelink
manga_title = manga_title.lower()
base_manga_page = basepagelink
In your Mangacanblog's __init__() function you are just setting local variables homepage, collection_page, etc, not instance variables, to make them instance variables you have to use self. , and this needs to be used in both super class as well as subclass.
But a better thing to do would be to call super(Manga_site).__init__() to let the super class handle its initialization, and then you can initialize sub class just the way you want to.
But for this, you would need to define Manga_site as a new style class, by inheriting from object class. Example -
class Manga_site(object):
def __init__(self,homepage,collection_page,base_manga_page,manga_title = ""):
self.homepage = homepage
self.collection_page = collection_page
self.base_manga_page = base_manga_page
self.manga_title = manga_title
class Mangacanblog(Manga_site):
def __init__(self,manga_title):
super(Mangacanblog, self).__init__(bloglink, collectionpagelink, basepagelink, manga_title.lower())
I have guessing you would define bloglink and collectionpagelink , before you use them in the subclass.
But this given, from the example you have given, what you are trying to achieve may be to use objects of class, and not inheritence.
Inheritence is used when the subclass has extra attributes/properties and extra methods.
You create different objects of same class if you want to store different data in them. Example -
class Manga_site:
def __init__(self,homepage,collection_page,base_manga_page,manga_title = ""):
self.homepage = homepage
self.collection_page = collection_page
self.base_manga_page = base_manga_page
self.manga_title = manga_title
mangacanblog = Manga_site('<homepage url>','<collection_page>',....)
anothermangasite = Manga_site('<another url>',....)
Then you can use these objects anyway you want to.
I wanted to get the values of self.request.get('foo') and etal everytime I create an instance of a class, so I decided to use __init__ constructor. Here's my code:
class archive(handler):
d = dict(title='',author= '')
def __init__(self):
self.d['title'] = self.request.get('title')
self.d['author'] = self.request.get('author')
class compose(handler):
def get(self):
self.render('compose.html')
def post(self):
a = archive()
My purpose is, to get rid the repetition of:
title = self.request.get('title')
author = self.request.get('author')
in every def post(self). But the problem is I get a NoneType error:
AttributeError: 'NoneType' object has no attribute 'get'
Obviously, self.request.get('title') returned None. I am just new with Python and Google Appengine.
Thank you guys.
This is how I managed to fix the problem:
class Archive(object):
d = dict(title='',author= '')
def load_d(self):
r = webapp2.get_request()
self.d['title'] = r.get('title')
self.d['author'] = r.get('author')
class Compose(Handler):
def get(self):
self.render('compose.html')
def post(self):
a = Archive()
a.load_d()
I assume you use webapp2.
Your init overrides the init of the webapp2 request handler (super). You can read in the webapp2 docs how to to this:
http://webapp-improved.appspot.com/guide/handlers.html#overriding-init
Take care when you use variables (self.variable) because you can also override variables of the request handler. You can use the request registry.
Hoi, this is my first post and I am pretty new to django.
[Edit: changed "from" to "mfrom"]
I have a generic class like
class Message(models.Model):
mfrom = models.TextField()
text = models.TextField()
def beautify(self, text):
'''replace emoticons with images'''
return text
def save(self, *args, **kwargs):
self.text = self.beautify(self.text)
super(Message, self).save(*args, **kwargs)
and I have a few sources where messages are coming from that need different handling, some (like XMPP) will come from non HTTP request sources, but external scripts.
So I thought I'd make subclasses of Message for the different types like
class MessageXMPP(Message):
def load_from_XMPP(self, xmppmsg):
self.mfrom = xmppmsg.mfrom
self.text = xmppmsg.text
class MessageJSON(Message):
def load_from_JSON(self, jsonmsg):
self.mfrom = jsonmsg.mfrom
self.text = jsonmsg.text
If I now call the save() method of the above two classes django tries to save it to the MessageXMPP resp. MessageJSON tables, while I want the data to be stored in the Message table (and not have MessageXMPP resp. MessageJSON tables created at all).
Is there a way to not create a Message object and copy the values over, but have the subclasses write to the Message table?
I don't really understand why you have separate model classes here. You should really just have one class with the different methods. Even better, since these are creation methods, you should define a custom Manager which returns the instantiated Message.
However, if you insist on having separate classes, you should make them proxy models so that they do not reference their own tables:
class MessageJSON(Message):
class Meta:
proxy = True
I have a UserModel class that will essentially do everything like login and update things.
I'm trying to pass the instance of itself (the full class) as an argument to another function of another class.
For example: (obviously not the code, but you get the idea)
from Car import CarFactory
class UserModel:
def __init__(self,username):
self.username = username
def settings(self,colour,age,height):
return {'colour':colour,'age':age,'height':height}
def updateCar(self,car_id):
c = CarFactory(car_id, <<this UserModel instance>>)
So, as you can see from the very last line above I would like to pass an instance of UserModel to the CarData class, so when within the CarData class I can access the UserModel.settings(), however, I am unsure of the syntax. I could of course just do:
c = CarFactory(car_id,self.settings)
Any help would be grateful appreciated.
Thanks
c = CarFactory(car_id, self)
doesnt work?
on a side note it would be self.settings() not self.settings ... unless you define settings to be a property
This was fixed in Django 1.9 with form_kwargs.
I have a Django Form that looks like this:
class ServiceForm(forms.Form):
option = forms.ModelChoiceField(queryset=ServiceOption.objects.none())
rate = forms.DecimalField(widget=custom_widgets.SmallField())
units = forms.IntegerField(min_value=1, widget=custom_widgets.SmallField())
def __init__(self, *args, **kwargs):
affiliate = kwargs.pop('affiliate')
super(ServiceForm, self).__init__(*args, **kwargs)
self.fields["option"].queryset = ServiceOption.objects.filter(affiliate=affiliate)
I call this form with something like this:
form = ServiceForm(affiliate=request.affiliate)
Where request.affiliate is the logged in user. This works as intended.
My problem is that I now want to turn this single form into a formset. What I can't figure out is how I can pass the affiliate information to the individual forms when creating the formset. According to the docs to make a formset out of this I need to do something like this:
ServiceFormSet = forms.formsets.formset_factory(ServiceForm, extra=3)
And then I need to create it like this:
formset = ServiceFormSet()
Now how can I pass affiliate=request.affiliate to the individual forms this way?
Official Document Way
Django 2.0:
ArticleFormSet = formset_factory(MyArticleForm)
formset = ArticleFormSet(form_kwargs={'user': request.user})
https://docs.djangoproject.com/en/2.0/topics/forms/formsets/#passing-custom-parameters-to-formset-forms
I would use functools.partial and functools.wraps:
from functools import partial, wraps
from django.forms.formsets import formset_factory
ServiceFormSet = formset_factory(wraps(ServiceForm)(partial(ServiceForm, affiliate=request.affiliate)), extra=3)
I think this is the cleanest approach, and doesn't affect ServiceForm in any way (i.e. by making it difficult to subclass).
I would build the form class dynamically in a function, so that it has access to the affiliate via closure:
def make_service_form(affiliate):
class ServiceForm(forms.Form):
option = forms.ModelChoiceField(
queryset=ServiceOption.objects.filter(affiliate=affiliate))
rate = forms.DecimalField(widget=custom_widgets.SmallField())
units = forms.IntegerField(min_value=1,
widget=custom_widgets.SmallField())
return ServiceForm
As a bonus, you don't have to rewrite the queryset in the option field. The downside is that subclassing is a little funky. (Any subclass has to be made in a similar way.)
edit:
In response to a comment, you can call this function about any place you would use the class name:
def view(request):
affiliate = get_object_or_404(id=request.GET.get('id'))
formset_cls = formset_factory(make_service_form(affiliate))
formset = formset_cls(request.POST)
...
This is what worked for me, Django 1.7:
from django.utils.functional import curry
lols = {'lols':'lols'}
formset = modelformset_factory(MyModel, form=myForm, extra=0)
formset.form = staticmethod(curry(MyForm, lols=lols))
return formset
#form.py
class MyForm(forms.ModelForm):
def __init__(self, lols, *args, **kwargs):
Hope it helps someone, took me long enough to figure it out ;)
I like the closure solution for being "cleaner" and more Pythonic (so +1 to mmarshall answer) but Django forms also have a callback mechanism you can use for filtering querysets in formsets.
It's also not documented, which I think is an indicator the Django devs might not like it as much.
So you basically create your formset the same but add the callback:
ServiceFormSet = forms.formsets.formset_factory(
ServiceForm, extra=3, formfield_callback=Callback('option', affiliate).cb)
This is creating an instance of a class that looks like this:
class Callback(object):
def __init__(self, field_name, aff):
self._field_name = field_name
self._aff = aff
def cb(self, field, **kwargs):
nf = field.formfield(**kwargs)
if field.name == self._field_name: # this is 'options' field
nf.queryset = ServiceOption.objects.filter(affiliate=self._aff)
return nf
This should give you the general idea. It's a little more complex making the callback an object method like this, but gives you a little more flexibility as opposed to doing a simple function callback.
I wanted to place this as a comment to Carl Meyers answer, but since that requires points I just placed it here. This took me 2 hours to figure out so I hope it will help someone.
A note about using the inlineformset_factory.
I used that solution my self and it worked perfect, until I tried it with the inlineformset_factory. I was running Django 1.0.2 and got some strange KeyError exception. I upgraded to latest trunk and it worked direct.
I can now use it similar to this:
BookFormSet = inlineformset_factory(Author, Book, form=BookForm)
BookFormSet.form = staticmethod(curry(BookForm, user=request.user))
As of commit e091c18f50266097f648efc7cac2503968e9d217 on Tue Aug 14 23:44:46 2012 +0200 the accepted solution can't work anymore.
The current version of django.forms.models.modelform_factory() function uses a "type construction technique", calling the type() function on the passed form to get the metaclass type, then using the result to construct a class-object of its type on the fly::
# Instatiate type(form) in order to use the same metaclass as form.
return type(form)(class_name, (form,), form_class_attrs)
This means even a curryed or partial object passed instead of a form "causes the duck to bite you" so to speak: it'll call a function with the construction parameters of a ModelFormClass object, returning the error message::
function() argument 1 must be code, not str
To work around this I wrote a generator function that uses a closure to return a subclass of any class specified as first parameter, that then calls super.__init__ after updateing the kwargs with the ones supplied on the generator function's call::
def class_gen_with_kwarg(cls, **additionalkwargs):
"""class generator for subclasses with additional 'stored' parameters (in a closure)
This is required to use a formset_factory with a form that need additional
initialization parameters (see http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset)
"""
class ClassWithKwargs(cls):
def __init__(self, *args, **kwargs):
kwargs.update(additionalkwargs)
super(ClassWithKwargs, self).__init__(*args, **kwargs)
return ClassWithKwargs
Then in your code you'll call the form factory as::
MyFormSet = inlineformset_factory(ParentModel, Model,form = class_gen_with_kwarg(MyForm, user=self.request.user))
caveats:
this received very little testing, at least for now
supplied parameters could clash and overwrite those used by whatever code will use the object returned by the constructor
Carl Meyer's solution looks very elegant. I tried implementing it for modelformsets. I was under the impression that I could not call staticmethods within a class, but the following inexplicably works:
class MyModel(models.Model):
myField = models.CharField(max_length=10)
class MyForm(ModelForm):
_request = None
class Meta:
model = MyModel
def __init__(self,*args,**kwargs):
self._request = kwargs.pop('request', None)
super(MyForm,self).__init__(*args,**kwargs)
class MyFormsetBase(BaseModelFormSet):
_request = None
def __init__(self,*args,**kwargs):
self._request = kwargs.pop('request', None)
subFormClass = self.form
self.form = curry(subFormClass,request=self._request)
super(MyFormsetBase,self).__init__(*args,**kwargs)
MyFormset = modelformset_factory(MyModel,formset=MyFormsetBase,extra=1,max_num=10,can_delete=True)
MyFormset.form = staticmethod(curry(MyForm,request=MyFormsetBase._request))
In my view, if I do something like this:
formset = MyFormset(request.POST,queryset=MyModel.objects.all(),request=request)
Then the "request" keyword gets propagated to all of the member forms of my formset. I'm pleased, but I have no idea why this is working - it seems wrong. Any suggestions?
I spent some time trying to figure out this problem before I saw this posting.
The solution I came up with was the closure solution (and it is a solution I've used before with Django model forms).
I tried the curry() method as described above, but I just couldn't get it to work with Django 1.0 so in the end I reverted to the closure method.
The closure method is very neat and the only slight oddness is that the class definition is nested inside the view or another function. I think the fact that this looks odd to me is a hangup from my previous programming experience and I think someone with a background in more dynamic languages wouldn't bat an eyelid!
I had to do a similar thing. This is similar to the curry solution:
def form_with_my_variable(myvar):
class MyForm(ServiceForm):
def __init__(self, myvar=myvar, *args, **kwargs):
super(SeriveForm, self).__init__(myvar=myvar, *args, **kwargs)
return MyForm
factory = inlineformset_factory(..., form=form_with_my_variable(myvar), ... )
I'm a newbie here so I can't add comment. I hope this code will work too:
ServiceFormSet = formset_factory(ServiceForm, extra=3)
ServiceFormSet.formset = staticmethod(curry(ServiceForm, affiliate=request.affiliate))
as for adding additional parameters to the formset's BaseFormSet instead of form.
based on this answer I found more clear solution:
class ServiceForm(forms.Form):
option = forms.ModelChoiceField(
queryset=ServiceOption.objects.filter(affiliate=self.affiliate))
rate = forms.DecimalField(widget=custom_widgets.SmallField())
units = forms.IntegerField(min_value=1,
widget=custom_widgets.SmallField())
#staticmethod
def make_service_form(affiliate):
self.affiliate = affiliate
return ServiceForm
And run it in view like
formset_factory(form=ServiceForm.make_service_form(affiliate))