What is 'success_url' variable default value - django

I am creating a form in Django by extending the CreateView class and everything works fine.
But what I don't quite understand is that when the form is submitted, web browser automatically redirects me to the url specified by model's get_absolute_url() method.
Is it a default behavior that 'success_url' field is at some point assigned by an url returned by that method?

If your view class defines a success_url attribute this is used as the success url. Otherwise it will use get_absolute_url() method of the created/edited object. See the documentation here.
So if you don't want to redirect to the object's absolute url you can either define success_url on the class or re-define the class' get_success_url() method if you need to fine-tune it more.

Related

Django PermissionRequiredMixin not working

When I place the PermissionRequiredMixin as the most left paramenter, my requests get forwarded to the login URL even though the request is coming from an already authenticated user.
class ExampleViewSet(PermissionRequiredMixin, viewsets.ModelViewSet):
permission_required = ('example.example_view',)
When I place the PermissionRequiredMixin after the ModelViewSet the authenticated user is detected, however, the permission_required is ignored, and every user without the permission is allowed as well. And this answer suggested, that this is caused by the placement of the parameter, which leads to the first problem.
class ExampleViewSet(viewsets.ModelViewSet, PermissionRequiredMixin):
permission_required = ('example.example_view',)
How do I solve this problem?
It is not a problem. Order of inheritance classes is important. View base class have to set at last position. Mixins by theirs positions can override some function of the django view. The ordering of overriding function by the child class is in part defined by this ordering. First parent in the order will be called at first.
In your case, if you put a breakpoint in your PermissionRequiredMixin, you will see that python does not pass in it when you call your page
You can read some links as:
https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem
http://python-history.blogspot.com/2010/06/method-resolution-order.html
How does Python's super() work with multiple inheritance?

DRF: How to access "context" inside custom DecimalField class?

I am subclassing the DecimalField class from Django RestFramework and need to access context. Formatting for decimal fields includes settings that are user-selectable, so I need to access the user object (which, I assume, should be inside context) inside the to_representation() method.
Via debug, I've looked at all properties of self inside my CustomDecimalField class, but, of course, I can't see class methods, so I don't know if there's an appropriate "get" method to get context. I've tried self.context (as a property), self.get_context(), and self.getcontext(), but none worked.
I found this announcement re: require_context:
https://www.django-rest-framework.org/community/3.11-announcement/
...but it seems to be valid only for validation and default value methods.
This seems like such a simple thing; hard to believe it is so difficult.
You have to manually set the user inside the context. So, in your view:
serializer = YourSerializer(your_data, context={'user': request.user})
And you will then be able to access it in your to_representation() method:
def to_representation(self, instance):
user = self.context.get("user")
Please see the documentation for more information.

Dynamic get_absolute_url using url query parameters

Big picture: I'd like my reverse method in get_absolute_url (see below) to return a url with a query parameter appended to it at the end, e.g. <url>?foo=bar. Further, I'd like bar to be specified by the POST request that triggered the call to get_absolute_url, either as an input to the form (but not a field represented by the model, something temporary) or as a url query parameter. I am easily able to access bar in my view using either method, but I can't seem to figure out how to access it in my model.
The motivation here is that my detail page splits up the fields from my model into different tabs using javascript (think https://www.w3schools.com/howto/howto_js_tabs.asp). When the user is updating the model, they choose which tab they want to update, and then the update template only renders the fields from the model which are related to that tab. More importantly, after the user submits the update, I want the detail page to know to open the specific tab that the user just edited.
(I understand how this works if the field is a part of the model; in get_absolute_url with parameters, the solution is pretty straightforward and involves using self.id. In my case though, bar is not a part of the model and I can't figure out how else to access it)
Some specifics: I have a model in my project called Context. I have implemented a generic DetailView and an update page for the model using a modelform called ContextForm and a generic UpdateView called ContextUpdate. Once the form is submitted, I redirect to the detail page using get_absolute_url in models.py:
def get_absolute_url(self):
return reverse("context:review",kwargs={"slug": self.slug})
My urlpatterns in urls.py looks something like:
urlpatterns = [
url(r'^(?P<slug>[-\w]+)$',views.ContextDetail.as_view(),name="review"),
url(r'^(?P<slug>[\w]+)/edit$',views.ContextUpdate.as_view(),name="edit"),
]
I am able to access this parameter in my UpdateView quite easily:
def post(self,request,**kwargs):
print (request.POST.get("bar")) #accessing input to form
print (request.GET.get("bar")) #accesssing url parameter
return super().post(request,**kwargs)
But when get_absolute_url is called inside the model, it seems I no longer have access to it.
Any suggestions for how to accomplish this? I want to use get_absolute_url (along with modelforms, generic views, etc.) so that I can follow Django conventions, but it seems like using get_absolute_url is making the functionality that I want difficult to accomplish. If the redirect to the detail view following the POST request were to happen inside my view, then I would know how to solve this (I think). Any thoughts or ideas would be greatly appreciated!
As you say, you can't access the request inside your get_absolute_url method. Therefore you should override get_success_url, from which you can access it.
def get_success_url(self):
return reverse(reverse("context:review", kwargs={"slug": self.object.slug}) + '?bar=%s' % self.request.GET.get('bar')
Or if you want to re-use get_absolute_url:
def get_success_url(self):
return self.object.get_absolute_url + '?bar=%s' % self.request.GET.get('bar')
The second option is DRYer but would break if get_absolute_url was changed to include a querystring like ?foo=foo.

django update forms, who pass object id?

I've tried to create a simple ModelForm, and I notice that even if I pass an instance for update like that
mymodel = MyModel.objects.get(pk=1)
MyModelForm(instance=mymodel)
django does not create an hidden field or include in some way the pk of the object in the template. So I need to pass this by myself?
I prefer not passing the my id's like 1,2,3.. to the templates, so I would prefer passing something like uuid, or using signing.dumps(object_id), and then signing.loads(object_id), from django signing library.
So if I want to include this id in my template with the form POST data,
I didn't understand who is exactly responsible for the retrieve of that id - Is that the view or the form itself?
By view I mean to the built-ins FormView, or UpdateView, how these views find the object id? Assume to store the output of signing.dumps(object_id) in a hidden field
By the time you are in the template the form construction has completed. You can try accessing form.instance.id if its modelForm.
However, most likely you do not need the pk in the template, do you ? You can also inject a hidden form field with the instance pk value if you like. Why do you need the pk in the template ?
If you want to redirect to another page from the POST data you will have access to the object pk in the view itself.
According to official documentation the Built-in Views inherit from django.views.generic.detail.SingleObjectTemplateResponseMixin class which requires the views it is mixed with to provide a self.object attribute.

Adding custom variables into the request object in Django Middleware without using request.session

Is there a recommended way to pass a variable to all my views? Namely in my case, I want to pass a UserProfile object that Foreign Keys a django.contrib.auth.models.User object. I find most if not all my views need to pull the UserProfile object and putting it in Middleware seems like the way to go. It seems like I could do something like the following (I've seen a couple of solutions online that suggest it):
request.session['userprofile'] = userprofile_object
I don't like this because if my UserProfile model ever has a non-serializable field, it would break request.session.
If you have the AuthenticationMiddleware enabled, you will have a user object in all your views. To get the profile all you need to do is call user.get_profile in your view. For example, to output the id of the profile, you would do {{ user.get_profile.id }}.
If you would prefer not to call the get_profile function of the user object each time, you can add arbitrary items to your request. You would create a new middleware which would simply set
request.user_profile = request.user.get_profile()
Then just register that middleware in your settings.py and you should be good to go. I have used this method in the past for getting user geolocation data pinned to the request object.
This proposal depends on the assumption that userprofile objects only matter when users are already logged in so you can get the logged in user via request.user.
It should be possible to get the userprofile by travelling the foreignkey key relation in reverse like this:
if request.user.is_authenticated():
request.user.userprofile_object_set.all() #gets all related userprofile objects
else:
#...