(Comments)
Let us consider a scenario where we create user profile and update/edit the profile of a user using Django forms.
Let us add a simple UserProfile model.
from django.contrib.auth.models import User class UserProfile(models.Model): # Let us add some simple fields to profile user = models.OneToOneField(User) city = models.CharField(max_length=100) country = models.CharField(max_length=10) def __unicode__(self): return u"%s" % self.user
Now, let us add forms.
class UserProfileForm(forms.ModelForm): class Meta: model = UserProfile fields = ('city', 'country') #Note that we didn't mention user field here. def save(self, user=None): user_profile = super(UserProfileForm, self).save(commit=False) if user: user_profile.user = user user_profile.save() return user_profile
We did not add "user" in the fields because it is not something that the user adds/selects in the user interface. It should be filled with the currently logged in user so for that purpose we have overridden save method of UserProfileForm. If you observe the save method, we are first trying to get the user profile object without saving it to database(commit=False). This is to make sure that the application doesnt raise IntegrityError(which means we are trying to save to db without entering/filling mandatory fields). Then we are setting the user and then saving to database.
Let us add views to "add new profile" for a user:
from django.views.generic import FormView class NewUserProfileView(FormView): template_name = "profiles/user_profile.html" form_class = UserProfileForm def form_valid(self, form): form.save(self.request.user) return super(NewUserProfileView, self).form_valid(form) def get_success_url(self, *args, **kwargs): return reverse("some url name")
We have overridden form_valid method of NewUserProfileView and passed request.user (current loggedin user) to save method that we have overridden above. Since we cant access request object in models/forms, we need to pass to save method.(we can also pass to init method of form, thats another way).
Now, let us add another view to update the profile object.
from django.views.generic import UpdateView class EditUserProfileView(UpdateView) #Note that we are using UpdateView and not FormView model = UserProfile form_class = UserProfileForm template_name = "profiles/user_profile.html" def get_object(self, *args, **kwargs): user = get_object_or_404(User, pk=self.kwargs['pk']) # We can also get user object using self.request.user but that doesnt work # for other models. return user.userprofile def get_success_url(self, *args, **kwargs): return reverse("some url name")
urls.py
url(r'^profiles/new/$', NewUserProfileView.as_view(), name="new-user-profile"), url(r'^users/(?P<pk>\d+)/edit/$', EditUserProfileView.as_view(), name="edit-user-profile"),
Basic Django template to make above forms work:
<form method="post"> {% csrf_token %} {{ form.as_p }} <input type=submit value="submit" /> </form>
In EditUserProfileView, we have not overridden form_valid because that is not necessary in our case. UpdateView calls form.save() by default. Since we need not pass the current user to form.save() for an existing profile (as per overridden save method), we need not override form_valid.
Note that we have overridden get_object method because we want to show user id in url rather than profile id but UserProfile is the model for the view(we added model=UserProfile in EditUserProfileView). As per the default get_object method of EditUserProfileView, the "pk" in url refers to the pk of the model UserProfile. But we want to pass user id/pk in url rather than userprofile id. So, we have to override get_object.
We develop web applications to our customers using python/django/angular.
Contact us at hello@cowhite.com
Comments