Manipulate object after generic 'create_object' view (python/django) - python

Is it possible to manually add field entries to an object that has been created with the generic view?
Eg,
from django.views.generic.create_update import create_object
def create_thing(request):
queryset = Things.objects.all()
#Somehow pass something to tell the view to
#assign Thing.author=request.user...
return create_object(
request,
queryset,
form_class = ThingForm,
template_name = 'thing_template.html',
)
Ta!

Sorry, no. You'll have to write your own view.
Here's the source - you can see that there's no callback or anything, and nothing that gets passed both the request (so you can access request.user) and the new_object that you could possibly override to do the assignment.

Related

Django: tie two redirects to a single Update button depending on where the user came from

So, i have a rather usual "update item" page that is a class-based view which inherits UpdateView. (in views.py it looks like "class ItemUpdateView(UpdateView) and it has method get_success_url(self) defined which contains the redirect url where user will be taken after clicking "Update" button.
My problem is that in my application, there are two different pages that could lead me to this "Update item" page, and depending on the page that user comes from - i want to take the user back to either pageA or pageB upon the successful update of the item.
I wasn't able to find the best-practices of how to handle this anywhere on the web, so - would really appreciate the help.
My guess is that I need to create an additional parameter that will be a part of the url and will contain A or B depending on the pageA or pageB that user came from, i.e. the url itself would be something like '/itemUpdate/int:pk/sourcepage' => '/itemUpdate/45/A'. Does that sound like a correct aproach or is there a better way?
There is a better way that you can check Meta dictionary in request:
write in your views file:
class ItemUpdateView(UpdateView):
previous_url = ''
form_class = UpdateItem
def get(self, request, *args, **kwargs):
self.previous_url = request.META.get('HTTP_REFERER')
print(self.previous_url)
return super().get(request, *args, **kwargs)
def get_initial(self):
initial = super().get_initial()
initial['success_url'] = self.previous_url
return initial
def form_valid(self, form):
self.success_url = form.cleaned_data['success_url']
print(self.success_url)
return super().form_valid(form)
# also you can use get_success_url instead of form_valid()
# def get_success_url(self):
# return super().get_form().cleaned_data['success_url']
and then write a hidden field in your form and name it success_url
class UpdateItem(forms.ModelForm):
success_url = forms.URLField(widget=forms.HiddenInput)
class Meta:
model=Item
fields=['itemName','quantity']
Note you can not use instance in order to get success_url field, because this field belong to form nor your model instance !
refer to documentions

How can I reference a form when overriding a GET request in a class based view?

I overrode the GET request function handler in this class based view. In my else statement, I need to pass, as context data, the form that the class naturally creates (if I had not overridden the GET function). How can I do that?
I did not create a form at forms.py to create a form for the Post model. I let the create class based view handle the form creation for me. So, how can I get this form and pass as context data.
The only way I can think of doing this is creating a function based view and avoid using this class based view in this circumstance.
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ["title", "content", "payment_option", "price"]
def get(self, request):
card_set = BillingProfile.objects.get(user=request.user).card_set.all()
if not card_set.exists():
# The user does NOT have an inserted payment method.
return redirect("/billing/payment-method?next=/post/new/")
else:
# The user DOES have an inserted payment method.
form = "???"
return render(request, "posting/post_form.html", {"form":form})
You could use the method the class provides, which is self.get_form().
But this actually wouldn't be the right thing to do. What your should really do is to delegate to the default implementation of get and let it do what it normally would.
if not card_set.exists():
# The user does NOT have an inserted payment method.
return redirect("/billing/payment-method?next=/post/new/")
else:
return super().get(request)

Updating a Single Object Field in Django View

Edited: I am trying to update the value of a single field inside one of Django's objects. Here is the code:
class TodoCompleteView(generic.DetailView):
queryset = Todo.objects.all()
def get_object(self):
# Call the superclass
object = super(TodoCompleteView, self).get_object()
# Record the last accessed date
object.todo_completed = True
object.save()
# Return the object
return object
However, I keep getting an error:
TemplateDoesNotExist at /8/complete
list/todo_detail.html
How can avoid this? I simply want this view to flip a certain value in DB.
You inherit view from DetailView class, which by default is to view some models and not to change. Also, apparently, you use GET request to change the data. This is the wrong approach.
Alternatively I advise you to try to make inherit your view from SingleObjectMixin and View and manually create a handler for POST request.
I would rewrite your example like this:
from django.views.generic import View
from django.views.generic.detail import SingleObjectMixin
class TodoCompleteView(SingleObjectMixin, View):
model = Todo
def post(self, *args, **kwargs):
self.object = self.get_object()
self.object.todo_completed = True
self.object.save(update_fields=('todo_completed', ))
return HttpResponse(status=204)
P.S. you get the error, because DetailView subclassed from SingleObjectTemplateResponseMixin which tries to render the template called <model_name>_detail.html.

Django how to iterate through a list of objects in a view?

So I have a view that asks the user for input and I cannot figure out what to do to somehow iterate through the list and get the user input on all the objects...
def get(self, request, language, word):
'''Get reqeust to edit taken in steps'''
context = cache.get(word)
form_class = DefinitionInfoForm
context['form_class'] = form_class
return render(request,
'study/add_info.html',
context_instance=RequestContext(request, context))
Here is my get that is inside a CBV. I have loaded a cache of objects and I would like to somehow iterate through them one at a time making a new get for every one if possible
OR
do a bulk ad and render them all with forms and modify all the objects in the post method
I am using this form to add the info and I can not figure out how to do it with a bulk or one at a time...
class DefinitionInfoForm(forms.Form):
part_of_speech = forms.CharField(required=True, label=_(u'Part of Speech'))
pronunciation = forms.CharField(required=True, label=_(u'Pronunciation'))
In this case the answer for me was to use https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/#model-formsets and add a queryset as an argument.
I could then pass it to the template as context and iterate through the formset there

Accessing URL variables in Django 1.5 class-based view

I'm migrating a project from Django 1.2 to Django 1.5. The project used function-based views such as this:
def notecard_product(request, stockcode):
if request.user.is_authenticated():
liked = Recommendation.objects.values_list('product_id',flat=True).filter(recommended=True, user=request.user)
unliked = Recommendation.objects.values_list('product_id',flat=True).filter(recommended=False, user=request.user)
extra_context = {"liked" : liked, "unliked":unliked}
else:
extra_context = {"liked" : [0], "unliked": [0]}
return object_detail(request, queryset=Product.objects.live(),
object_id=stockcode,
extra_context=extra_context,
template_name='products/notecard.html', template_object_name='notecard_product')`enter code here`
In this excerpt, stockcode is captured from the URL and used to determine object_id. So I'm wondering how I would do this in a class-based view. This is what I have so far:
class NotecardProductListView(ListView):
queryset=Product.objects.live()
pk=self.kwargs['stockcode']
template_name='products/notecard.html'
context_object_name='notecard_product'
def get_context_data(self, **kwargs):
context = super(BooksListView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated():
liked = Recommendation.objects.values_list('product_id',flat=True).filter(recommended=True, user=self.request.user)
unliked = Recommendation.objects.values_list('product_id',flat=True).filter(recommended=False, user=self.request.user)
extra_context = {"liked" : liked, "unliked":unliked}
else:
extra_context = {"liked" : [0], "unliked": [0]}
context.update(extra_context)
return context
pk is the new name for the old object_id kwarg. Obviously, this code doesn't work, because I can't access self outside of a function. But I'm not really sure how to do this. I need to set pk to something in the keyword arguments, but can't find a way to do this, as pk needs to be set in the class body outside of any functions. I also don't really have a way to experiment and try things, because the entire project is broken right now due to deprecated function calls.
Thanks!
I'm not sure where you got the idea that pk is the new name for object_id, nor why you think that you need to set it to a value per request. The point of the class-level attributes in class-based views is that they are set per view class, not per instance: they refer to the place the view will go to look up the value, not the actual value itself.
Your first mistake is that the equivalent of the old object-detail view is, not surprisingly, DetailView, not ListView. As the documentation shows, ListView gets the ability to show an object detail via its inheritance from the SingleObjectMixin. That mixin expects a class-level attribute called pk_url_kwarg, which is the name of the argument captured from the URL which identifies the object's PK: in your case, this is the string 'stockcode'. The instance itself takes care of looking up that value in any particular request, you don't need to do it.

Categories