Why do we have template_name = None as class variable here?(from django source code)
It's because if self.template_name is None, would raise an error?
(self.template_name would look for instance variable and if it's not there, would return the class variable)
If so, wouldn't it be better to have def __init__(self): self.template_name = None ?
class TemplateResponseMixin(object):
"""
A mixin that can be used to render a template.
"""
template_name = None
response_class = TemplateResponse
def render_to_response(self, context, **response_kwargs):
"""
Returns a response with a template rendered with the given context.
"""
return self.response_class(
request = self.request,
template = self.get_template_names(),
context = context,
**response_kwargs
)
def get_template_names(self):
"""
Returns a list of template names to be used for the request. Must return
a list. May not be called if render_to_response is overridden.
"""
if self.template_name is None:
raise ImproperlyConfigured(
"TemplateResponseMixin requires either a definition of "
"'template_name' or an implementation of 'get_template_names()'")
else:
return [self.template_name]
TemplateResponseMixin is a mixin which is not using an init, to make it easier to use in a mutiple inheritence. It does not need its own state, so it does not need a constructor. This also makes the inheritence easier because you don' t need to call a constructor on it in your subclass.
The template_name is set as a class instance obviously because there is no constructor. It implies that it should be set from the subclass. Also, changing the value of it will affect all future instances of that mixin.
Related
It's an example that's as similar as possible, and it's not exactly the same as the actual code.
But I believe it's easy to understand.
class Fruits:
...
def get_sample_data(self, df):
...
data = {
'put_file_attachment': >here<,
}
...
class DataInputForm(forms.Form):
attachment = forms.FileField()
class MyView(FormView):
template_name = 'view.html'
form_class = DataInputForm
def get_success_url(self):
return str(
reverse_lazy("milk")
)
def post(self, request, *args, **kwargs):
get_file = request.FILES.get('attachment')
...
k = Fruits()
k.load_data()
return self.render_to_response(context)
I would like to bring the attachment(In fact, get_file) that the user attached to the web class Fruits's >here<
In other words, I would like to save the file(get_file) in DB column (put_file_attachment) by the user's attachment. How can I get a value passed to a request from another class to another class?
I tried to get 'get_file' by creating a MyView object in the Fruit class, but it doesn't work.
Is that possible in this structure or Am I not understanding the concept of request??
The variable must be explicitly passed to the class for it to be available. It's currently in a different scope, so it won't be available.
So, either refactor your Fruits class to take your file as an argument to your constructor (ie, __init__), or pass it in some other way, such as a parameter to your load_data method.
More generally speaking I want add a custom admin Panel to list some related content. To lookup this related content I need to pass the current instance of the model or at least its ID to this panel. How can I do that within these lists in which these admin panels are noted?
Here is my specific example of an ArtistPage. In the editor I would like to add a panel to list WorkPages that are related to this ArtistPage:
from wagtail.models import Page
class ArtistPage(Page):
# ...
content_panels = [
# ...
ListWorksPanel(artist=self), # This doesn’t work
]
The panel itself is defined like that, mostly copied from the HelpPanel:
from wagtail.admin.panels import Panel
class ListWorksPanel(Panel):
def __init__(self, artist="", template="admin/list_works_panel.html", **kwargs,):
super().__init__(**kwargs)
self.artist = artist
self.template = template
def clone_kwargs(self):
kwargs = super().clone_kwargs()
del kwargs["help_text"]
kwargs.update(
artist=self.artist,
template=self.template,
)
return kwargs
class BoundPanel(Panel.BoundPanel):
def __init__(self, panel, instance, request, form):
super().__init__(panel, instance, request, form)
self.template_name = self.panel.template
self.artist = self.panel.artist
This is more a general Python question, I think. I know how to pass "self" in functions. But how does that work here with this class as element of a list? I reckon that the __init__() method of the ArtistPage is the way to go, but I cannot figure out how exactly.
What is the pythonic way of passing "self" to another class?
Update (Solution):
Following #gasman’s aswer, I just added the get_context_data method to the BoundPanel class. The works are accessible in the template of the panel now!
class ListWorksPanel(Panel):
def __init__(self, artist="", template="admin/list_works_panel.html", **kwargs,):
super().__init__(**kwargs)
self.artist = artist
self.template = template
def clone_kwargs(self):
kwargs = super().clone_kwargs()
del kwargs["help_text"]
kwargs.update(
artist=self.artist,
template=self.template,
)
return kwargs
class BoundPanel(Panel.BoundPanel):
def __init__(self, panel, instance, request, form):
super().__init__(panel, instance, request, form)
self.template_name = self.panel.template
self.artist = self.panel.artist
def get_context_data(self, parent_context):
context = super().get_context_data(parent_context)
context['works'] = self.instance.works.all() # exactly what I needed
return context
The ArtistPage instance is passed to BoundPanel.__init__ as the keyword argument instance. All code that deals with an individual ArtistPage needs to be written inside the BoundPanel class.
When you write ListWorksPanel() as part of a content_panels definition, you're creating a ListWorksPanel instance that then becomes part of the definition of the ArtistPage class. At this point in the code, no actual instance of ArtistPage exists, so there's no self to refer to. Effectively, there's a single ListWorksPanel object shared by all ArtistPage instances that will ever be created.
When the time comes to render the edit form for an individual page, Wagtail calls get_bound_panel on the ListWorksPanel object, passing the page instance along with the form and request objects. (The full process is explained here.) This returns an instance of BoundPanel, which is a template component that performs the final rendering. In this case, you probably want to define a get_context_data method on BoundPanel that does something like context['works'] = self.instance.works.all() - this will then make the variable works available on the template.
I'm following along with a Django Rest Framework tutorial (source code here) and I have a few questions about the below code snippet:
class ReviewCreate(generics.CreateAPIView):
serializer_class = ReviewSerializer
permission_classes = [IsAuthenticated]
throttle_classes = [ReviewCreateThrottle]
def get_queryset(self):
return Review.objects.all()
def perform_create(self, serializer):
pk = self.kwargs.get('pk')
watchlist = WatchList.objects.get(pk=pk)
review_user = self.request.user
review_queryset = Review.objects.filter(watchlist=watchlist, review_user=review_user)
if review_queryset.exists():
raise ValidationError("You have already reviewed this movie!")
if watchlist.number_rating == 0:
watchlist.avg_rating = serializer.validated_data['rating']
else:
watchlist.avg_rating = (watchlist.avg_rating + serializer.validated_data['rating'])/2
watchlist.number_rating = watchlist.number_rating + 1
watchlist.save()
serializer.save(watchlist=watchlist, review_user=review_user)
In the class definition, the variable serializer_class is declared; however in the perform_create method, serializer is an argument. Given the differences in naming, how are these two related?
In the method perform_create, self.kwargs is referenced. However, I don't see a kwargs argument passed to any __init__ method or else attached to the class object. How/where is kwargs passed to the class?
In both cases, I can only assume that the inherited class (generics.CreateAPIView) has an __init__ method that assigns a serializer_class variable to serializer. How it "listens" for a child class definition of serializer_class, I have no idea. And as for kwargs, I'm at a loss for how this is passed to the child class w/o explicitly calling defining it in its arguments.
Edit, this question Kwargs in Django does not answer my question-- it just explains what keyword arguments are. I'm not confused about their name, I'm confused by their invisible yet implicit reference in this code.
Answering your first point, we have to note two things:
First, the method perform_create is used in the create method associated to CreateModelMixin (see https://github.com/encode/django-rest-framework/blob/71e6c30034a1dd35a39ca74f86c371713e762c79/rest_framework/mixins.py#L16). The class CreateAPIView inherits from this mixin and also from GenericAPIView(See https://github.com/encode/django-rest-framework/blob/b1004a47334a0dd1929e6d50b8f7ff6badc959f4/rest_framework/generics.py#L184). As you can see, the create method mentioned above uses the class perform_create method and needs a serializer there. Defining perform_create without that argument would lead to an error when creating objects with this method.
Another thing to note is that the serializer used comes from the get_serializer method. Checking the source code for GenericAPIView (https://github.com/encode/django-rest-framework/blob/b1004a47334a0dd1929e6d50b8f7ff6badc959f4/rest_framework/generics.py#L103) we can see that this method calls get_serializer_class which retrieves the serializer defined by serializer_class.
In conclusion, if you don't modify anything else, the serializer that will be passed as a parameter will be an instance of you serializer class defined in serializer_class.
Getting to your second point, if you try to search the parent class of GenericAPIView and follow on searching the base class from which these classes inherit, you will end up finding that the base class is View from django.views.generic. There you will find in the setup method (https://github.com/django/django/blob/27aa7035f57f0db30b6632e4274e18b430906799/django/views/generic/base.py#L124) where the kwargs attribute is initialized. Also you can see in this method's code documentation the following statement:
"""Initialize attributes shared by all view methods."""
Thus in any view we create (if it has View as its base class) we will always be able to manipulate self.request, self.args and self.kwargs. I hope I explained myself clearly!
Why when i call instance of model from method car_name the method return - in Django admin.
#admin.register(Invoice)
class CarProductDataAdmin(admin.ModelAdmin):
form = CarProductDataAdminForm
def car_name(self, obj):
# Call this instance
car = Customer.objects.get(product__customer_id=self.request.user.person.id)
return "car.name" # return string
readonly_fields = ('car_name', )
But when i just return string it is work.
#admin.register(Invoice)
class CarProductDataAdmin(admin.ModelAdmin):
form = CarProductDataAdminForm
def car_name(self, obj):
# Doesn`t Call this instance
# return string
return "name"
readonly_fields = ('car_name', )
From my judgement the django admin seems to fail silently when encountering an exception in a method, which is used as a field.
In your first example the problem seems to be self.request, as the CarProductDataAdmin instance does not have a request attribute. So instead of raising an exception no value is returned to the field resulting in an output "-".
If you need the request you must get it from somewhere and save it in your ModelAdmin for re-use. Maybe by overring the get_form method of the ModelAdmin
class CarProductDataAdmin(admin.ModelAdmin):
# ....
def get_form(self, request, obj=None, change=False, **kwargs):
self.request = request
return super().get_form(request, obj, change, **kwargs)
Then you should be able to use your car_name method as posted in your code.
First noticeable problem in your code is that instead of object attribute value you are returning a string:
return "car.name" # return string
should be:
return f"{car.name}"
or, depending on python version you are using:
return f"{}".format(car.name)
Next one is that calling get on model manager should cause DoesNotExists exception but in some situations it could be suppressed so I'll advice to modify the code to:
try:
car = Customer.objects.get(product__customer_id=self.request.user.person.id)
return f"{car.name}"
except Customer.DoesNotExists:
return "None"
And see if that return what you want or "None"
I am trying to define a base request handling class so that the webapp pages may inherit some basic methods and variable which otherwise would be required to be repeatedly be defined for each page of the application. A sort of similar functionality like django preprocessors. This is my base class from which other pages inherit:
class BasePage(webapp.RequestHandler):
def __init__(self):
self.user = users.get_current_user()
self.template_values = {
'user': self.user,
'environ': self, #I don't like the idea of passing the whole environ object to a template
##The below three functions cannot be executed during _init_ because of absence of self.request
#'openid_providers': self.openid_providers(),
#'logout_url': self.get_logout_url(),
#'request': self.get_request(),
}
##A sort of similar functionality like render_to_response in django
def render_template(self, template_name, values = None, *args, **kwargs):
#PATH is the directory containing the templates
if values:
for value in values: self.template_values[value] = values[value]
self.response.out.write(template.render(PATH+template_name, self.template_values, *args, **kwargs))
##Returns request as the name suggests
def logout_url(self):
return users.create_logout_url(self.request.url)
##Returns request as the name suggests
def request(self):
return request
##Returns openid login urls
def openid_providers(self):
#OPENID_POVIDERS is a list of dictionary
for p in OPENID_PROVIDERS:
p['login_url'] = users.create_login_url(self.request.get('next', '/') , p['name'], p['url'])
return OPENID_PROVIDERS
Everything is working fine except that I cannot pass some variables during initialization as self.request is not available. So for a workaround what I did is pass on whole self variable as a template variable.
Is there some other way to provide the template variables (request, logout_url etc) to the templates?
A much simpler solution than bgporter's is to do the common setup in the initialize method of webapp.RequestHandler. Here's an example from work, where we wanted to add a Django-like is_ajax method to the request object:
class BaseHandler(webapp.RequestHandler):
def initialize(self, request, response):
super(BaseHandler, self).initialize(request, response)
# Add a Django-like is_ajax() method to the request object
request.is_ajax = lambda: \
request.environ.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
This method is called to, uh, initialize each request handler with the current request and response objects, before the appropriate get or post (or whatever) methods are called.
I've solved that problem in my AppEngine code by using the Template Method Pattern
Basically, the base class looks like:
class MyBasePage(webapp.RequestHandler):
def __init__(self):
# common setup/init stuff here,
# omitted for this discussion
def Setup(self):
# request handling setup code needed in both GET/POST methods, like
# checking for user login, getting session cookies, etc.
# omitted for this discussion
def get(self, *args):
self.Setup()
# call the derived class' 'DoGet' method that actually has
# the logic inside it
self.DoGet(*args)
def post(self, *args):
self.Setup()
# call the derived class' 'DoPost' method
self.DoPost(*args)
def DoGet(self, *args):
''' derived classes override this method and
put all of their GET logic inside. Base class does nothing.'''
pass
def DoPost(self, *args):
''' derived classes override this method and
put all of their POST logic inside. Base class does nothing.'''
pass
...your derived classes then mostly just need to worry about the guts of those DoGet() and DoPost() methods.