I think I have a simple case here but I'm not finding good examples of the implementation ( or probably failing to understand).
After the user (not logged in) types his username to a form, Django would generate a unique URL based of this data (encoded in URL?) for the user that can be accessed once and within 5 minutes. Based on that URL (after clicking it) the data (username) would be decoded and ready for use in this one-time view.
Simple scenario if needed: user nimda fills the form and then is redirected (for example) to a view that shows the generated URL. Then nimda clicks the generated URL and a view is shown with the data he or she typed into the form
If you don't need that url you could save data to the session and send the user to a specific url.
The view connected to the url generates content depending on the (anonymous) users session. The user can see the content as long as you sessions last or you implement a time stamp an check this before delivering content.
If you need the url:
Build a model connected with the sessions with url and a time stamp.
Configure the urls.py for the url-model like
url(r'^dataUrl/(?P[0-9]+)/$', PostDelete.as_view()),
Assign the user session and the entered data (saved to the session) with
the url-model.
When delivering the content check for the random-url-part, and the timestamp and deliver the date (or not ;) )
You can access the session in a cvb's like this:
class YourClassName(TemplateView):
template_name = ""
def get_context_data(self, **kwargs):
context = super(YourClassName , self).get_context_data(**kwargs)
DataYouNeed = self.request.session["SessionVariableOfTheUser"]
userDAta = self.request.user #if this is usefull `
or in a createView:
class URLCreate(CreateView):
model = randomUrl
template_name = "entryCreate.html"
success_url = "../xyz/"
form_class = UrlCreateForm
# if you like to change the success-url
def get_success_url(self):
#print dir(self.object.instance)
#print self.object.instance.id
url = "../bringMeTo/%s" % self.object.instance.id
return url
def form_valid(self,form):
form.instance.user = self.request.user
self.request.session["formData"]= form.instance
return super(URLCreate, self).form_valid(form)
pass
This is not a ready solution! Just an inspiration for a start.
Related
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
I'm working with an e-commerce webapp and in the product detailed-view I want to give the option to set the quantity before the checkout. I thought I could do this with a simple form:
class QuantityForm(forms.Form):
quantity = forms.IntegerField(widget=forms.NumberInput(attrs={'class':'required'}))
And then implementing it to the view:
class BagDetailView(DetailView):
context_object_name = 'ctx'
model = Bag
template_name = 'product_page.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = QuantityForm(initial={'quantity':1})
context['Jackson'] = Bag.objects.get(title = 'Jackson')
context['Anthony'] = Bag.objects.get(title = 'Anthony')
return context
But the problem is the POST request. I cannot call the render() function because I have another view to handle the checkout, so I need to call redirect(). This is the code:
def post(self, *args, **kwargs):
form = QuantityForm()
b = Bag.objects.get(slug=kwargs['slug'])
if form.is_valid:
return redirect(b)# calls get_absolute_url which redirects to checkout/<slug>
And I cannot access the data that I'm posting in the other view. I think it's bad practise to post data like this to another view, but I couldn't come up with anything but that. Is there any other way to pass that data into the other view?
Note: I'm not using a cart system because I'm only dealing with two products.
I am not sure if I have understood correctly, maybe you can do something like this.
In the template for increasing quantity, you can put this:
<i class="">INCREASE QUANTITY</i>
When the user clicks this, a function will be called:
#login_required
def add_to_checkout(request, slug):
#get the checkout for this customer which is not fulfilled
#increase the quantity
#redirect to checkout page
Another idea can be using session. You can increase the amount in the detail page and save it to the sessions, then use in the checkout page.
I hope I have understood correctly your question.
So i'm trying to build something, so that users would be able to report something on site. Here's the model,
class Report(models.Model):
reporting_url = models.URLField()
message = models.TextField()
I created Form for this Model including 'message' field only because 'reporting_url' is something it needs to populate by itself depending upon the specific page from where user has clicked "Report" button.
def report(request):
url_report = ???
if request.method == 'POST':
form = ReportForm(request.POST or None)
if form.is_valid():
new_form = form.save(commit=False)
new_form.reporting_url = url_report
new_form.save()
I was wondering How can I pass the specific url to 'reporting_url' field in form depending on the Page from where user has clicked "Report" button? (Much like s we see on social Networks).
Am I doing this correctly, Or is there a better way for doing this?
Please help me with this code. Thanks in Advance!
If there is a report button on that specific page then I believe you could write custom context processor.
More info: Django: get URL of current page, including parameters, in a template
https://docs.djangoproject.com/en/1.11/ref/templates/api/
Or maybe just write it directly in the views.py in your function and set
url_report = request.get_full_path()
I think you can use the form on the same page of the URL and use:
url_report = request.get_full_path()
in the view, to get the current URL.
Else if you want to create a separate view for the reporting form. You can use
url_report = request.META.get('HTTP_REFERER')
to get the previous or refering URL which led the user to that page.
request.META.get('HTTP_REFERER') will return None if it come from a different website.
i have a very simple model... something like this:
class MachineTransTable(models.Model):
...
file = models.ForeignKey('File', related_name='the_file')
source = models.TextField()
target = models.TextField()
...
What I'd like to do is to have a page where the user has the source on the left (disable), the target on the right (editable) and a submit button to post the edited target text for EACH selected object in the MachineTransTable table. Here are some more information to better understand my request:
A page refers to a single file and there are several (sometimes hundreds) of objects in the MachineTransTable table belonging to the same file
Each time the user edit a single target and hit the submit button for that object, the object is saved/updated (depending on the initial value of the object) in the DB and the the user can continue to edit all the other objects...
At the end of the page there is another submit button which is used to exit from the page at the end of the work (all the objects have been edited/updated). If an object has not been edited/updated, it keeps its original value.
I tried to use a formset but I guess it's not the right choice... This is the file forms.py
class SegmentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SegmentForm, self).__init__(*args, **kwargs)
if self.instance.id:
self.fields['source'].widget.attrs['readonly'] = True
class Meta:
model = MachineTransTable
fields = ['source','target',]
SegmentFormSet = inlineformset_factory(File, MachineTransTable, form=SegmentForm, fields=('source','target'), extra=0)
and the view.py file is:
class CatUpdateView(LoginRequiredMixin,UpdateView):
Model = MachineTransTable
context_object_name = 'file'
template_name = 'app_cat/cat.html'
form_class = SegmentForm
...
def get_context_data(self, **kwargs):
context = super(CatUpdateView, self).get_context_data(**kwargs)
formset = SegmentFormSet(instance=self.get_object())
context['formset_Segment'] = formset
return context
Using this approach, I have a single form and all the related objects are saved/updated at once when the submit button is hit...
What can I do to achieve what I described above? Thanks
I think your choice is correct, you should not use several (hundreds eventually) forms here if the field in the same model. For two reasons:
You have to do a lot of repeat job to write so many forms and that is easy to make mistake and hard to maintain.
You still have to connect the database and update the record no matter how many field had been edit, and they almost efficiency.
But if you really want to do this,you can just use Ajax to post the current parameters name to the api, then update it, For instance, you have a button for target field:
value_in_the_html
Use Ajax to post the field name and value:
$ajax({
url: "api/table_id",
type: "POST",
datatype: "json",
data: {"field": "target", "value": "value_in_the_html"}
});
In view.py:
def UpdateTable(request, id):
field = request.POST.get("field", None)
value = request.POST.get("value", None)
machine = MachineTransTable.objects.filter(id=id).first()
machine.getattr(machine,field) = value
machine.save()
return HttpResponse("Saved!")
I'm just starting with formsets and I have trouble making a user friendly error system.
So the user sees a list view that shows him all instances of a model already written into a formset. This pages is meant to show him the data and edit it as well.
Before I was using a lot of individual forms with a save button for every form. But now I want to improve it to have a formset that provides a single save button for all of the forms.
But there comes my problem: Before I used to send the user via "action" to another url (e.g. .../update/ ) which processes the request and then sends him back to the list view he saw before. That's to avoid multiple submits when hitting F5.
But now if I do this and only a single form is wrong all the information the user had entered is lost.
So instead I stopped using the extra URL and made the processing part of the list view. Now I can use form.error on every form, but also the user resubmits when hitting F5.
Is there a way to have both?
Also: I have 1 extra form. But if the user changes it, and I feed the POST data into the formset, save it and then put it back to the page I lost the extra formset, because now the former extra is showing the newly entered instance and there is no true extra field left until the page is refreshed without sending post data.
Here is my View:
class BVServerListView(View):
def get(self, request):
eigene_server = Server.objects.filter(user=request.user)
EigeneServerFormset = modelformset_factory(Server, extra=1, form=ServerForm)
eigene_server_formset = EigeneServerFormset(queryset=eigene_server)
context = {'eigene_server': eigene_server_formset,}
return render(request, 'bildverteiler/server_list.html', context)
def post(self, request):
eigene_server = Server.objects.filter(user=request.user)
EigeneServerFormset = modelformset_factory(Server, extra=1, form=ServerForm)
eigene_server_formset = EigeneServerFormset(request.POST, request.FILES)
for form in eigene_server_formset.forms:
if form.data.get('delete', False):
server = Server.objects.get(user=request.user, name=form.data['name'])
server.delete()
else:
if form.has_changed() and form.is_valid():
server = form.save(commit=False)
server.user = request.user
server.save()
context = {'eigene_server': eigene_server_formset,}
return render(request, 'bildverteiler/server_list.html', context)
There is no difference between using a single form or a formset here. The answer is the same: post to the same view, but redirect after a successful save.
The other thing that you are doing wrong here is to validate and save individual forms one by one. Don't do that, because you could end up with a situation that the first forms are valid and get saved, but subsequent ones are invalid and therefore the formset needs to be redisplayed. Instead, validate the formset as a whole:
if eigene_server_formset.is_valid():
for form in eigene_server_formset.forms:
if form.cleaned_data.get('delete'):
... delete ...
else:
form.save()
return HttpResponseRedirect('somewhere_else')
return render...