django update forms, who pass object id? - django

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.

Related

How to map HTML form data to Django model

I have a (quite complex) HTML form full of logic that triggers based on different choices in the selectpickers with fields that don't have quite the same names as the corresponding fields in the Django model, and sometimes I fear that I will need to add some logic when it comes to going from the data sent from the HTML form and to the Django model. I realise that I can probably not use a ModelForm in Django to handle this and have been looking for some examples of using the standard django.forms.Form to map the HTML form into my model but I haven't really found much. Can someone give me some hints?
It sounds as though your html form already exists and somehow you want to read in the POST data from that form. Without making any further assumptions as to how you ended up with an html form without a django ModelForm or forms.Form output via a view - as long as the form action location is mapped via a route to a view - the view can then process the request.POST data. Again all form validation goodness of django is out the door if you did not use django forms (model or forms based) and you have to do your own validations in the view then. Once the form data has been validated, initialize your model object like this: my_obj = ModelName(field_name1=form_input_data1, field_name2=form_input_data2, ...) and that's it. Then you can do my_obj.save().
Now let's say, it's not so bad. You actually are using the forms.Form inheritance to create your django-istic form class which has no direct relationship with the model. Now you can use the form related validation clean_field and clean steps etc... as well as all the built-in field types internal validation django automatically does. Then when you read in the POST data - do whatever it takes to map the form fields (via any transformation as necessary) to the django model object you are trying to construct, keeping in mind the default values and any model save custom assignments that may happen.
You can not just map a html form into your django model. You need to create a model form first and then render it in html.
If you want to somehow map your html form to model. First render your ModelForm in html. Create the exact copy of the html format of your django form and use it in html. Catch that in your view and process it like model form. But anyway you have to create the ModelForm.

Sending extra data to templates using class-based views in Django

I have recently started using Django frameworks class-based views.
Assume I have a model Book. Is it possible using class-based views, to besides sending one object of type Book, send a boolean value, which I could set in the view?
For example, I would like the view to send the dictionary context = {object: Book, green: True} to a template.
Yes, of course it's possible.
You can override get_context_data and add anything you like.
Edit
get_object gets the specific database object that the view is displaying/editing. In the default implementation, get_context_data returns a dictionary consisting of the value returned by get_object. You can call the superclass method then add your own values to the result.

Get an url pk in a generic RESTful view?

I'm trying to manage my REST API like that :
http://xxx/users/userid[0-9]+/projects/projectid[0-9]+/tasks/taskid[0-9]+/
So I can access the JSON easily in my website. But, the thing is, I defined my view classes using the REST framework generic views. For example, here is my UserDetail view :
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
But of course I don't want all my users to be displayed, I just want my user with the ID userid to be displayed. I don't really know how to do it, I tried
queryset = User.objects.filter(id=userid)
but of course userid is not defined... Any help please ?
Edit : just to clarify, here is the url that leads to this view :
url(r'^users/(?P<pku>[0-9]+)/$', views.UserDetail.as_view(
), name='user-detail'),
First of all, If you want to use class based views, you should read some more about them. They are thoroughly explained on Django's docs and you can read about the specific generics of the framework you're using on the REST framework docs too. I'm not saying that you haven't read those, just that you seem to be missing some basic concepts that are explained there.
Now, to the problem at hand, if you look at the doc's of the generic view you're extending, you can see that it represents the endpoints for a single instance, meaning that it won't act on all your model's instances (as you seem to assume).
Also, you can see that this view is built on top of a series of other classes, the more critical one being GenericAPIView. On there you can see two things:
The queryset class field in this context is meant for filtering the posible instances you can manipulate, not obtaining the specific instance described on your url.
The lookup_field is the field that defines which attribute from your model will be used for getting the actual instance. You should define this field to whatever field you're going to use on your url to identify your object (generally it's pk). It's also important to note that the url should include a keyword argument corresponding to this value.
Internally, the view will take care of calling the get_object method, which usese the lookup_field value to find the specific model, and then feed that object to the serializer and return the result back to the client.
DISCLAIMER: I've never used Django REST framework, I put this answer togheter by reading the relevants docs and based on my experience.
I guess you need this:
Resolve function (django 1.4)
Then in your view class method you can do:
temp1, args, kwargs = resolve(self.request.path)

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:
#...

Django Class-Based Generic Views and ModelForms

Like much documentation on generic views in Django, I can't find docs that explicitly describe how to use the new Class-Based Generic Views with Django Forms.
How is it done?
What have you tried so far? The class based views are pretty new, and the docs don't have a lot of examples, so I think you're going to need to get your hands dirty and experiment!
If you want to update an existing object, then try using UpdateView. Look at the mixins it uses (e.g ModelFormMixin, SingleObjectMixin, FormMixin) to see which methods you can/have to override.
Good luck!
The easiest way to use model forms with class based views is to pass in the model and keep a slug / pk captured in url, in which case you will not need to write any view code.
url(r'^myurl/$', CreateView.as_view(model=mymodel))
#Creates a model form for model mymodel
url(r'^myurl/(?<pk>\w+)/$', UpdateView.as_view(model=mymodel))
#Creates a model form for model mymodel and updates the object having pk as specified in url
url(r'^myurl/(?<slug>\w+)/$', DeleteView.as_view(model=mymodel, slug_field="myfield"))
#Creates a model form for model mymodel and deletes the object denoted by mymodel.objects.get(my_field=slug)
You can also override methods to obtain more complex logic. You can also pass a queryset instead of a model object.
Another way is to create a modelform in forms.py and then pass form_class to the url as
url(r'^myurl/$', CreateView.as_view(form_class=myform))
This method allows you to define form functions as well as Meta attributes for the form.