What is the user's username? - django

In one of my Django models, I override the save function. I do this to get the user's username. But that keeps failing.
this is what i did:
def save(self, *args, **kwargs):
self.slug = slugify('%s' % (self.question))
if not self.id:
self.publish_date = datetime.datetime.now()
self.publisher = self.request.user
self.modification_date = datetime.datetime.now()
self.modifier = self.request.user
super(Faq, self).save(*args, **kwargs) # Call the "real" save() method
This fails with:
'Faq' object has no attribute 'request'
Thanks.

If this is for use within the Admin app, as you say in your answer to Jake, then you shouldn't override the model save method at all. Instead, you should override the save_model method of the ModelAdmin class.
See the original code in django.contrib.admin.options - you'll see that it's already passed the request object. So all you need to do is to assign the publisher there:
def save_model(self, request, obj, form, change):
obj.slug = slugify('%s' % (obj.question))
if not obj.id:
obj.publish_date = datetime.datetime.now()
obj.publisher = request.user
obj.modification_date = datetime.datetime.now()
obj.modifier = request.user
obj.save()

request is only passed to views, not model methods so you will have to set the publisher in a view.
I would remove the line self.modifier = self.request.user from here and set modifier = request.user at the same time as you set question which I assume you are doing in a view.
Then you can change self.publisher = self.request.user to self.publisher = self.modifier
Hope that helps.

You'll need to pass the request into the save method since it doesn't exist in that context automatically.
def save(self, request, *args, **kwargs):
self.slug = slugify('%s' % (self.question))
if not self.id:
self.publish_date = datetime.datetime.now()
self.publisher = request.user
self.modification_date = datetime.datetime.now()
self.modifier = self.request.user
super(Faq, self).save(*args, **kwargs) # Call the "real" save() method
Usage...
my_faq = Faq()
my_faq.save(request)

Related

Conflict in form save() method when inherit from other save() method in Django

I changed the save method in the Django form.Then I inherited another save method from this method and made some changes to the child method ,that conflicted. I can't figure out how to fix the conflict so that my other uses of the parent method stay healthy and don't get spoiled.
Forms.py
class BaseModelForm(forms.ModelForm):
def save(self, commit=True, **kwargs):
"""
Save this form's self.instance object if commit=True. Otherwise, add
a save_m2m() method to the form which can be called after the instance
is saved manually at a later time. Return the model instance.
"""
if self.errors:
raise ValueError(
"The %s could not be %s because the data didn't validate." % (
self.instance._meta.object_name,
'created' if self.instance._state.adding else 'changed',
)
)
if commit:
# If committing, save the instance and the m2m data immediately.
self.instance.save(user=kwargs.pop('user'))
self._save_m2m()
else:
# If not committing, add a method to the form to allow deferred
# saving of m2m data.
self.save_m2m = self._save_m2m
return self.instance
class ChildForm(BaseModelForm):
def save(self, commit=True, **kwargs):
new_instance = super(ChildForm, self).save(commit=True)
# Some other codes goes here!
return new_instance
Models.py
class BaseFieldsModel(models.Model):
def save(self, *args, **kwargs):
user = kwargs.pop('user', None)
if user:
if self.pk is None:
self.created_by = user
self.updated_by = user
super(BaseFieldsModel, self).save(*args, **kwargs)
Views.py
def my_view(request,id):
if form.is_valid():
instance = form.save(commit=False)
# Some codes goes here!
instance.save(user=request.user)
And error is:
KeyError at /my/url
Request Method: POST
'user'
Exception Type: KeyError
Exception Value:
'user'
And Django Debug page separately highlight these three lines:
instance = form.save(commit=False)
new_instance = super(ChildForm, self).save(commit=True)
self.instance.save(user=kwargs.pop('user'))
You're trying to get user in BaseModelForm.save(), but you never passed the user to the form.save() calls. You need to add form.save(..., user=request.user):
def my_view(request,id):
...
instance = form.save(commit=False, user=request.user)
and also pass it along in super(ChildForm, self).save(..., **kwargs)
class ChildForm(BaseModelForm):
def save(self, commit=True, **kwargs):
new_instance = super(ChildForm, self).save(commit=True, **kwargs)
...
Also, you probably want to pass super(ChildForm, self).save(commit=commit, ...) in ChildForm:
new_instance = super(ChildForm, self).save(commit=True, **kwargs)
because otherwise the form class may not respect the commit flag being passed from the view (unless of course, you've already handled this in your elided code).

Add a field value outside form in Django

Whenever I have to add a value to the instance of a form obtained from the context or from the URL I do it in the following way, using form.instance.
class PreguntaForm(forms.ModelForm):
class Meta:
model = Pregunta
fields = ('etiqueta', 'grupo', 'tipo_pregunta', 'opciones', 'mostrar_tabla', 'activo')
def __init__(self, *args, **kwargs):
cuestionario = kwargs.pop('cuestionario', False)
super(PreguntaForm, self).__init__(*args, **kwargs)
self.fields['grupo'].queryset = Grupo.objects.filter(cuestionario=cuestionario)
class PreguntaNueva(InfoPregunta, CreateView):
form_class = PreguntaForm
encabezado = 'Nueva Pregunta'
model = Pregunta
def get_form_kwargs(self):
kwargs = super(PreguntaNueva, self).get_form_kwargs()
kwargs['cuestionario'] = self.dame_cuestionario()
return kwargs
def form_valid(self, form):
form.instance.cuestionario = self.dame_cuestionario()
return super(PreguntaNueva, self).form_valid(form)
The problem that arises now is that I want to perform a check CreateView and EditView. To DRY, I want to do it in the clean method of the model, but the value that I assign to form.instance.cuestionario, is not available within the clean method. How could I do it? This value must not be edited by the user in any case.
Yes it is, you pass it in via get_form_kwargs; you just need to assign it to an instance variable in the form's __init__.
def __init__(self, *args, **kwargs):
self.cuestionario = kwargs.pop('cuestionario', False)
super(PreguntaForm, self).__init__(*args, **kwargs)
self.fields['grupo'].queryset = Grupo.objects.filter(cuestionario=self.cuestionario)
def clean(self):
# do something with self.cuestionario

How to get the current user in ModelFormMixin post() method?

How do i get the currently logged in user in the following implementation of the LIstview and ModelFormMixin:
class ListMessages(ListView, ModelFormMixin):
model = Message
template_name = 'accounts/list_messages.html'
context_object_name = 'messages'
form_class = MessageHiddenUserForm
#success_url = reverse_lazy('accounts:list_messages', kwargs={'uname': })
def post(self, request, *args, **kwargs):
self.object = None
self.form = self.get_form(self.form_class)
if self.form.is_valid():
self.form.user_to = self.kwargs['uname']
self.form.user_from = request.user #this doesn't work
self.object = self.form.save()
return self.get(request, *args, **kwargs)
The problem is not where you get the user from, but where you assign it to. Setting arbitrary attributes on a form doesn't do anything at all; you need to assign it to the result of form.save.
obj = self.form.save(commit=False)
obj.user_to = self.kwargs['uname']
obj.user_from = request.user
obj.save()
Note, you must not call self.get() directly like that; you must always redirect after a successful post.
return redirect('accounts:list_messages', kwargs={...})
For method "post" use request.user.username to get current logged-in user.

How to pass ForeignKey value into initial data for Django form

I have a model like this:
class Job(models.Model):
slug = models.SlugField()
class Application(models.Model):
job = models.ForeignKey(Job)
And a view like this:
class ApplicationCreateView(CreateView):
model = Application
A user will view the job object (/jobs/<slug>/), then complete the application form for the job (/jobs/<slug>/apply/).
I'd like to pass application.job.slug as the initial value for the job field on the application form. I'd also like for the job object to be put in context for the ApplicationCreateView (to tell the user what job they're applying for).
How would I go about doing this in my view?
You may be interested in CreateView page of the fantastic http://ccbv.co.uk/ In this page, you can see in one glance which member methods and variables you can use.
In your case, you will be interested to override:
def get_initial(self):
# Call parent, add your slug, return data
initial_data = super(ApplicationCreateView, self).get_initial()
initial_data['slug'] = ... # Not sure about the syntax, print and test
return initial_data
def get_context_data(self, **kwargs):
# Call parent, add your job object to context, return context
context = super(ApplicationCreateView, self).get_context_data(**kwargs)
context['job'] = ...
return context
This has not been tested at all. You may need to play with it a little. Have fun.
I ended up doing the following in a function on my class:
class ApplicationCreateView(CreateView):
model = Application
form_class = ApplicationForm
success_url = 'submitted/'
def dispatch(self, *args, **kwargs):
self.job = get_object_or_404(Job, slug=kwargs['slug'])
return super(ApplicationCreateView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
#Get associated job and save
self.object = form.save(commit=False)
self.object.job = self.job
self.object.save()
return HttpResponseRedirect(self.get_success_url())
def get_context_data(self, *args, **kwargs):
context_data = super(ApplicationCreateView, self).get_context_data(*args, **kwargs)
context_data.update({'job': self.job})
return context_data

Return current user on details

I am trying to build an API view, to handle user management using django rest framework version 2.3.10 with django 1.6. I tried to build a ModelViewSet which based on the URL pk value it would return either current user or public user.
I tried to add a dispatch function which will assigned pk to current user, but it seems like this function is running too soon that its always seeing the user as anonymous
class UserViewSet(viewsets.ModelViewSet):
"""
"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsOwnerOrCreateOnly, )
def dispatch(self, request, *args, **kwargs):
if kwargs.get('pk') == 'current' and not request.user.is_anonymous():
kwargs['pk'] = request.user.pk
resp = super(CurrentUserViewSet, self).dispatch(request, *args, **kwargs)
return resp
I tried to do the below, which works
class UserViewSet(viewsets.ModelViewSet):
"""
"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsOwnerOrCreateOnly, )
def retrieve(self, request, *args, **kwargs):
if self.kwargs.get('pk') == u'current' and not request.user.is_anonymous():
self.kwargs['pk'] = request.user.pk
return super(CurrentUserViewSet, self).retrieve(request, *args, **kwargs)
but, I don't want to override each and every function on several ModelViewSet classes I have, so, is there a way to use something similar to the dispatcher whereby I can check if the pk is equal to "current" and then assign current user to it?
Another question, how can I change the returned fields programmatically? for example when querying current user I want to include the first and last name from the user model, but when querying by primary key, I want first and last name to not return as response? any suggestions on how todo that?
I got the same problem I solved it by using method "initial" instead of "dispatch"
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsOwnerOrCreateOnly, )
def initial(self, request, *args, **kwargs):
# logic - code #
if kwargs.get('pk') == 'current' and not request.user.is_anonymous():
kwargs['pk'] = request.user.pk
# end #
resp = super(CurrentUserViewSet, self).initial(request, *args, **kwargs)
return resp
see " dispatch "
method in https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/views.py
for better understanding.
Override viewsets.ModelViewSet class with your pk check implementation and use that new class, something like this:
class GenericUserViewSet(viewsets.ModelViewSet):
def retrieve(self, request, *args, **kwargs):
if self.kwargs.get('pk') == u'current' and not request.user.is_anonymous():
self.kwargs['pk'] = request.user.pk
return super(CurrentUserViewSet, self).retrieve(request, *args, **kwargs)
class UserViewSet(GenericUserViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsOwnerOrCreateOnly, )
And for the second question, perhaps creating two serializers (public and current) and changing serializer_class to either one of them in init of GenericUserViewSet may do the trick, I haven't tested this but it's an idea:
class GenericUserViewSet(viewsets.ModelViewSet):
def __init__(self, *args, **kwargs):
if self.kwargs.get('pk') == u'current' and not request.user.is_anonymous():
self.serializer_class = UserSerializer
else:
self.serializer_class = PublicUserSerializer
super(GenericUserViewSet, self).__init__(*args, **kwargs)
I'm assuming that you want to save the current user to your DB model, yes?
If so this should be fairly easy to fix, just add this method to your views:
def pre_save(self, obj):
obj.user = self.request.user
This will execute just before the model is saved. I use this all the time and it works great.
The other thing you can do is write a mixin class in a generic way that does want you want then inherit it in each of the views you need it in. Assuming that is that you have a solution that works, but just don't want to mimic you code all over the place.