Django class view: __init__ - python

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.

Related

how to override the .create() method inside a generic view (example: ListCreateAPIView) in django-rest-framework?

I wanted to override the create method in class-based view which implements the ListCreateAPIView , not generally while overriding methods like the get_queryset(self) method, the requests, the url **kwargs are accessed from self, but I wanted to override the .create() method of the CreateModelMixin, so I took a look at the code to find the signature as create(self, request, *args, **kwargs) what does django pass in the **kwargs, *args of this function? are these url **kwargs by any chance? How do I go about overriding the create method in the generic view asthe request in any function of the generic view is accessed from the self but the signature of the create function explicitly requires a request argument.
Following is DRF ListCreateAPIView, as you can see *args, **kwargs are directly passing down from standard post method:
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset or creating a model instance.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
Now, talking about overriding create from CreateModelMixin, you can simply override it as:
from rest_framework import generics
class YourWonderfulView(generics.ListCreateAPIView):
queryset = YourModelClass.objects.all()
serializer_class = YourSerializer
def create(self, request, *args, **kwargs): # don't need to `self.request` since `request` is available as a parameter.
# your custom implementation goes here
return Response(response) # `response` is your custom response – e.g. dict, list, list of dicts etc
Hope it helps :)
from rest_framework import generics
from tasks.models import Task
from tasks.serializers import TaskSerializer
class TaskList(generics.ListCreateAPIView):
queryset = Task.objects.all()
serializer_class = TaskSerializer
def create(self, request, *args,**kwargs):
# your implementation
return Response(response)

Inherit Variables from Parent Class

I am trying to work out how to inherit variables from a parent class.
I have two classes (simplified but same principle):
class Database(object):
def __init__(self, post, *args, **kwargs):
self.post = post
self.report()
def report(self):
#... obtain variables from post ...
self.database_id = self.post['id']
#... save data to database
class PDF(Database):
def __init__(self, post, *args, **kwargs):
Database.__init__(self, post, *args, **kwargs)
#... if i try to access self.database_id now, it returns an error ...
print(self.database_id)
instantiating script:
Database(request.POST)
PDF(request.POST)
I have tried just instantiating CreatePDF, as i thought the Database.__init__(self, post, *args, **kwargs) line would the Database class, but this does not work either.
I am trying to find the most pythonic way to do inherit. I can obviously obtain self.database_id from the post dict passed to PDF(), however I do not see the point in doing this twice, if I can use inheritance.
Thanks
Use:
class PDF(Database):
def __init__(self, post, *args, **kwargs):
# Stuff
super().__init__(post, *args, **kwargs)
The correct approach to instantiated an inherited class is to call super().init(args), which in this case calls Database.init because of method resolution order.
See http://amyboyle.ninja/Python-Inheritance

Use #staticmethod in Django Rest Framework endpoint method?

Should I be defining post, get, etc methods of a Django Rest Framework APIView as static?
class HomeView(APIView):
def get(request):
etc...
or
class HomeView(APIView):
#staticmethod
def get(request):
etc...
What are the pros/cons of each way?
Thank you
DRF does not declare get and post as static methods and neither should you. Here's how the defaults are configured in DRF generics.
It is common in DRF to reference instance methods such as self.get_object and self.get_serializer from within get and post.
class CreateAPIView(mixins.CreateModelMixin,
GenericAPIView):
"""
Concrete view for creating a model instance.
"""
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class ListAPIView(mixins.ListModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class RetrieveAPIView(mixins.RetrieveModelMixin,
GenericAPIView):
"""
Concrete view for retrieving a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
class DestroyAPIView(mixins.DestroyModelMixin,
GenericAPIView):
"""
Concrete view for deleting a model instance.
"""
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
class UpdateAPIView(mixins.UpdateModelMixin,
GenericAPIView):
"""
Concrete view for updating a model instance.
"""
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
As DRF document, You seems do not need to add #staticmethod decorator
DRF won't function correctly without passing ' self '.
PyCharm does mark these methods as 'maybe static', this is false!
Making them static breaks the calling of the method, since the caller method provides the 'self', and your method does not except it. Essentially your still get the self aliased as request, but your other args are ignored. It is possible that this happens silently, that makes it a fairly nasty bug to find :(.
In terms of performance a 'static' or regular function based view should be slightly faster, since you avoid the creation of the instance, but the difference is probably so small that it is hardly noticeable.

Use a method from other classes w/o inheritance

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.

How do I access the request object or any other variable in a form's clean() method?

I am trying to request.user for a form's clean method, but how can I access the request object? Can I modify the clean method to allow variables input?
The answer by Ber - storing it in threadlocals - is a very bad idea. There's absolutely no reason to do it this way.
A much better way is to override the form's __init__ method to take an extra keyword argument, request. This stores the request in the form, where it's required, and from where you can access it in your clean method.
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self.request ...
and in your view:
myform = MyForm(request.POST, request=request)
For what it's worth, if you're using Class Based Views, instead of function based views, override get_form_kwargs in your editing view. Example code for a custom CreateView:
from braces.views import LoginRequiredMixin
class MyModelCreateView(LoginRequiredMixin, CreateView):
template_name = 'example/create.html'
model = MyModel
form_class = MyModelForm
success_message = "%(my_object)s added to your site."
def get_form_kwargs(self):
kw = super(MyModelCreateView, self).get_form_kwargs()
kw['request'] = self.request # the trick!
return kw
def form_valid(self):
# do something
The above view code will make request available as one of the keyword arguments to the form's __init__ constructor function. Therefore in your ModelForm do:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
# important to "pop" added kwarg before call to parent's constructor
self.request = kwargs.pop('request')
super(MyModelForm, self).__init__(*args, **kwargs)
UPDATED 10/25/2011: I'm now using this with a dynamically created class instead of method, as Django 1.3 displays some weirdness otherwise.
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj, **kwargs)
class ModelFormWithRequest(ModelForm):
def __new__(cls, *args, **kwargs):
kwargs['request'] = request
return ModelForm(*args, **kwargs)
return ModelFormWithRequest
Then override MyCustomForm.__init__ as follows:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
You can then access the request object from any method of ModelForm with self.request.
The usual aproach is to store the request object in a thread-local reference using a middleware. Then you can access this from anywhere in you app, including the Form.clean() method.
Changing the signature of the Form.clean() method means you have you own, modified version of Django, which may not be what you want.
Thank middleware count look something like this:
import threading
_thread_locals = threading.local()
def get_current_request():
return getattr(_thread_locals, 'request', None)
class ThreadLocals(object):
"""
Middleware that gets various objects from the
request object and saves them in thread local storage.
"""
def process_request(self, request):
_thread_locals.request = request
Register this middleware as described in the Django docs
For Django admin, in Django 1.8
class MyModelAdmin(admin.ModelAdmin):
...
form = RedirectForm
def get_form(self, request, obj=None, **kwargs):
form = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
form.request = request
return form
I ran into this particular problem when customizing the admin. I wanted a certain field to be validated based on the particular admin's credentials.
Since I did not want to modify the view to pass the request as an argument to the form, the following is what I did:
class MyCustomForm(forms.ModelForm):
class Meta:
model = MyModel
def clean(self):
# make use of self.request here
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
def form_wrapper(*args, **kwargs):
a = ModelForm(*args, **kwargs)
a.request = request
return a
return form_wrapper
The answer by Daniel Roseman is still the best. However, I would use the first positional argument for the request instead of the keyword argument for a few reasons:
You don't run the risk of overriding a kwarg with the same name
The request is optional which is not right. The request attribute should never be None in this context.
You can cleanly pass the args and kwargs to the parent class without having to modify them.
Lastly, I would use a more unique name to avoid overriding an existing variable. Thus, My modified answer looks like:
class MyForm(forms.Form):
def __init__(self, request, *args, **kwargs):
self._my_request = request
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self._my_request ...
You can't always use this method (and its probably bad practice), but if you are only using the form in one view you could scope it inside the view method itself.
def my_view(request):
class ResetForm(forms.Form):
password = forms.CharField(required=True, widget=forms.PasswordInput())
def clean_password(self):
data = self.cleaned_data['password']
if not request.user.check_password(data):
raise forms.ValidationError("The password entered does not match your account password.")
return data
if request.method == 'POST':
form = ResetForm(request.POST, request.FILES)
if form.is_valid():
return HttpResponseRedirect("/")
else:
form = ResetForm()
return render_to_response(request, "reset.html")
fresh cheese from cheesebaker#pypi: django-requestprovider
I have another answer to this question as per your requirement you want to access the user into the clean method of the form.
You can Try this.
View.py
person=User.objects.get(id=person_id)
form=MyForm(request.POST,instance=person)
forms.py
def __init__(self,*arg,**kwargs):
self.instance=kwargs.get('instance',None)
if kwargs['instance'] is not None:
del kwargs['instance']
super(Myform, self).__init__(*args, **kwargs)
Now you can access the self.instance in any clean method in form.py
When you want to access it through "prepared" Django class views like CreateView there's a small trick to know (= the official solution doesn't work out of the box). In your own CreateView you'll have to add code like this:
class MyCreateView(LoginRequiredMixin, CreateView):
form_class = MyOwnForm
template_name = 'my_sample_create.html'
def get_form_kwargs(self):
result = super().get_form_kwargs()
result['request'] = self.request
return result
= in short this is the solution to pass request to your form with Django's Create/Update views.

Categories