I don't know how to pass values from url to the UpdateView. Then I need to pass that value to my html page.
Corresponding line in urls.py,
url(r'^poi/edit/(?P<pk>\d+)', POIFormUpdateView.as_view(), name='POIform-edit')
views.py
class POIFormUpdateView(UpdateView):
model = PointOfInterest
fields = ['name', 'vip', 'category', 'place', 'latitude', 'longitude', 'picture', 'website', 'description', 'phone', 'email']
template_name_suffix = '_update_form'
def get(self, request, *args, **kwargs):
print 'On POI get method'
print kwargs
super(POIFormUpdateView, self).get(request, *args, **kwargs)
Here I tried overriding the get method, and kwargs prints the expected dictionary but I don't know how to pass that dict to my update_form.html file.
update_form.html,
<form role="form" method="POST" action="/poi/edit/{{ pk }}" class="post-form form-horizontal">{% csrf_token %}
<!-- customizing form -->
{{ form|crispy }}
<!-- End of customization -->
<button type="submit" class="save btn btn-default btn-primary center-block">Save</button>
</form>
I have tried also by getting url from name like,
<form role="form" method="POST" action="{% url 'POIform-edit' %}"
But this also won't work.
Add argument object ID to the url:
<form role="form" method="POST" action="/poi/edit/{{ object.pk }}/" class="post-form form-horizontal">
ClassBasedView passes model_name as context_object, it should become:
<form role="form" method="POST" action="/poi/edit/{{ pointofinterest.pk }}/" class="post-form form-horizontal">
I use <input type='hidden' name='***' value="/poi/edit/{{ pk }}" /> to pass this value to the request. Then in def get(): you can get this using something like myurl=request.POST.get('***')
Related
I am trying to create a page with formset in it. So far I've gotten the following:
forms.py
class ContractorForm(forms.ModelForm):
class Meta:
model = Contractor
fields = [
'first_name', 'last_name', 'email', 'company_name',
]
views.py
class ContractorUpdateView(SimpleLoginRequiredMixin, TemplateView):
def get(self, request, *args, **kwargs):
"""Handle GET requests: instantiate a blank version of the form."""
ContractorFormSet = formset_factory(
Contractor)
contractor_formset = ContractorFormSet()
context = {"contractor_formset": contractor_formset}
return render(
request, "accounts/contractor_form.html", context)
contractor_form.html
<div class="card-body">
<form class="" method="post" action="" id="facility_contractor_form">
{% for form in contractor_formset %}
{% csrf_token %}
{{ form.as_p }}
{% endfor %}
</form>
</div>
<!-- /.card-body -->
<div class="card-footer">
Cancel
<input type="submit" form="facility_contractor_form" value="Save Changes"
class="btn btn-success float-right">
</div>
But when I try to open the page, I'll get the following error:
TypeError at /facility/2/contractor/
Contractor() got an unexpected keyword argument 'auto_id'
Any ideas? I think my using for maybe the wrong idea
Your ContractorUpdateView references the model, while it should reference the form, so it gotta be:
ContractorFormSet = formset_factory(ContractorForm)
[Base Update View details][1]
[1]: http://ccbv.co.uk/projects/Django/3.0/django.views.generic.edit/BaseUpdateView/
I am trying to have a Update form(updateview) in in my detailView template which updates one of the foreign key object of my detailview's object. I am getting output as expected and logics are working completely fine. I am using updateviewform as popup form but previous data is not getting prepopulated in the form.
Views.py file
class EducationUpdateView(LoginRequiredMixin,UpdateView):
model = Education
form_class= EducationCreateForm
class PortfolioDetailedView(DetailView):
model = Portfolio
success_url = 'portfolio:index'
def get_context_data(self, **kwargs):
context = super(PortfolioDetailedView, self).get_context_data(**kwargs)
context['education_form'] = EducationCreateForm()
return context
template
here portfolio is the detailsView object and education is its foreign key
{% for item in portfolio.education.all %} <form method="POST" class="form-group" action="{%url 'portfolio:eduupdate' pk=item.pk %}"
{% csrf_token %}
<div class="form-row">
{% bootstrap_form form %}
</div>
<input type="Submit" class="btn btn-primary" value="Submit"> </form>
pasting this for an idea this is not complete code.
The only problem is data is not getting prepopulated into update view form
I am very new in Python and Django. A am trying to make app but I have an issue.
Can anyone help me, please xD
I can't get id of authenticated user...
I tried it in this way, and many other ways...
views.py
class CreateProfile(CreateView):
template_name = 'layout/add_photo.html'
model = Profile
fields = ['image', 'user']
html
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="username"> #Here has to be field filled in with logged in user
<input type="file" name="image">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">Save Changes</button>
</div>
</div>
</form>
And when I'm starting app, and want to change/add picture, I can do it for anyone from my database, not only for logged in user.
enter image description here
Thanks for patience and help!
In the Django ClassBasedViews you can get your user's id as self.request.user.id and in your template as {{ user.id }}
To check if someone is authenticated you can use self.request.user.is_authenticated() and in your template {% if user.is_authenticated %} .. {% endif %}
class CreateProfile(CreateView):
template_name = 'layout/add_photo.html'
model = Profile
fields = ['image', 'user']
# For example, if you want to return to a certain user
# profile (which requires url adjustments to take a Primary Key)
def get_success_url(self):
user_id = self.request.user.id # Get user_id from request
return reverse_lazy('git_project:user_profile', kwargs={'id': user_id})
When placing 2 forms in a view using the form|crispy filter and this answer to handle 2 forms in a single view: Proper way to handle multiple forms on one page in Django I am getting this error.
views.py:
def test_form(request):
if not request.user.is_authenticated():
return redirect(settings.LOGIN_URL)
title = 'test form'
row_control_form = RowControlForm(request.POST or None)
entry_form = EntryForm(request.POST or None)
context = {
'title': title,
'row_control_form': row_control_form,
'entry_form': entry_form,
}
if 'row_control_submit' in request.POST:
if row_control_form.is_valid():
row_control_form.save()
if 'entry_submit' in request.POST:
if entry_form.is_valid():
entry_form.save()
return render(request, "timesheet/test_form.html", context)
forms.py
class RowControlForm(forms.ModelForm):
class Meta:
model = RowControl
fields = ['month_control_record', 'department', 'activity', 'notes']
def clean(self):
cleaned_data = self.cleaned_data
# Ensures row is unique
try:
RowControl.objects.get(month_control_record=cleaned_data['month_control_record'],
department=cleaned_data['department'],
activity=cleaned_data['activity'],
notes=cleaned_data['notes'])
except RowControl.DoesNotExist:
pass
else:
raise ValidationError('This row already exists')
# Always return cleaned data
return cleaned_data
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['row_control', 'date', 'hours']
def clean(self):
cleaned_data = self.cleaned_data
# Ensures data is unique (only 1 hours entry for each date and row_control)
try:
Entry.objects.get(row_control=cleaned_data['row_control'],
date=cleaned_data['date'])
except Entry.DoesNotExist:
pass
else:
raise ValidationError('This entry already exists')
# Always return cleaned data
return cleaned_data
test_form.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-md-6 col-md-offset-3">
<h1 class="page-header"> Form Test </h1>
<form method="POST" action="{{ request.path }}">
{% csrf_token %}
{{ row_control_form|crispy }}
<button class="btn btn-primary" type="submit" value="Submit" name="row_control_submit" ><i class="fa fa-lg fa-floppy-o"></i> Save</button> </form>
</br>
</div>
<div class="col-md-6 col-md-offset-3">
<h1 class="page-header"> Form Test </h1>
<form method="POST" action="{{ request.path }}">
{% csrf_token %}
{{ entry_form|crispy }}
<button class="btn btn-primary" type="submit" value="Submit" name="entry_submit" ><i class="fa fa-lg fa-floppy-o"></i> Save</button> </form>
</br>
</div>
{% endblock %}
To provide context to the error:
Line 42 of forms.py is:
Entry.objects.get(row_control=cleaned_data['row_control'],
EDIT: Further investigation has shown that the issue is that both form validations are being run no matter which submit button is pressed, the request.POST when submitting valid data for the RowControlForm is:
<QueryDict: {'csrfmiddlewaretoken': ['HffmmbI31Oe0tItYDfYC4MoULQHL0KvF'], 'notes': ['Cool'], 'row_control_submit': ['Submit'], 'month_control_record': ['1'], 'department': ['1'], 'activity': ['1']}>
Therefore entry_submit is not in the request.POST and that validation should not run yet it is?
Firstly, you need to fix this line of your form's clean method
def clean(self):
...
Entry.objects.get(row_control=cleaned_data['row_control'],
You can't assume that row_control will be in the cleaned_data. You either need to add a check if 'row_control' in cleaned_data or catch the KeyError, then update the rest of the method appropriately. You should fix this, even though you didn't see this error until you put multiple forms on one page. It shouldn't be possible to cause a 500 server error by leaving a value out of a POST request. Users could do this even if there is only one form on the page.
Validation is running for both forms, because you are instantiating both forms with the post data, regardless of which submit button was pressed.
row_control_form = RowControlForm(request.POST or None)
entry_form = EntryForm(request.POST or None)
You should only use the POST data for the form you wish to submit.
row_control_form = RowControlForm()
entry_form = EntryForm()
if 'row_control_submit' in request.POST:
row_control_form = RowControlForm(request.POST)
if row_control_form.is_valid():
if 'entry_submit' in request.POST:
entry_form = EntryForm(request.POST)
if entry_form.is_valid():
entry_form.save()
Finally, it's good practice to redirect the user once they have successfully submitted a valid form.
I have a login form that I want to be available in all my views, so I created a context processor to add this form to every loaded context.
The problem is that {% csrf_token %} on the form template won't render the hidden input tag with the CSRF token value.
This is the context_processor order in settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.request',
'django.core.context_processors.csrf',
'absolute.context_processors.absolute',
'myproject.app.context_processors.base',
)
And then the processor itself on app/context_processors.py:
from django.contrib.auth.forms import AuthenticationForm
def base(request):
context = dict()
if not request.user.is_authenticated():
context['login_form'] = AuthenticationForm()
return context
The form template:
{% load i18n %}
<form method="post" action="{% url "django.contrib.auth.views.login" %}">
{% csrf_token %}
<input type="hidden" name="next" value="{% if request.GET.next %}{{ request.GET.next }}{% else %}{{ request.get_full_path }}{% endif %}" />
{{ login_form.as_p }}
<input type="submit" class="button success expand" value="{% trans 'Login' %}" />
</form>
The HTML output for this form:
<form action="/accounts/login/" method="post">
<input type="hidden" value="/" name="next">
<p><label for="id_username">Usuário:</label> <input type="text" name="username" maxlength="254" id="id_username"></p>
<p><label for="id_password">Senha:</label> <input type="password" name="password" id="id_password"></p>
<input type="submit" value="Login" class="button success expand">
</form>
And the error I get when submitting it:
CSRF verification failed. Request aborted.
However, and as I'm only using class-based views, if I add a csrf_protect decorator the form will work, but like this I would have to declare the dispatch method in all my views:
from django.views.decorators.csrf import csrf_protect
class HomeView(TemplateView):
template_name = 'home.html'
#method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
return super(HomeView, self).dispatch(*args, **kwargs)
Problem status
I gave up from putting the AuthenticationForm on all my views by creating a login form page. Anyway, it would still be awesome if someone could help me find a solution for this problem.
I've spent a couple of hours fighting an issue similar to the one you've described here. The {% csrf_token %} wasn't rendering anything and I was seeing this when in debug mode:
defaulttags.py:66: UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.
I was using a simple view that inherited from a TemplateView:
class MenuIndexView(TemplateView):
template_name = 'menu/index.html'
def get_context_data(self, **kwargs):
kwargs = super().get_context_data(**kwargs)
session = self.request.session
kwargs['zip_code'] = session.get('zip_code')
kwargs['calendar'] = helpers.get_menu_calendar(date.today() + timedelta(days=1), timedelta(days=14))
kwargs['forms'] = {'zip_code': forms.ZipCodeForm({'zip_code': session.get('zip_code')})}
return kwargs
After fussing around a bit under Django's I realized that pretty much no context at all was available where the tag was being generated (CsrfTokeNode on Django's defaulttags.py file):
class CsrfTokenNode(Node):
def render(self, context):
csrf_token = context.get('csrf_token', None)
if csrf_token:
if csrf_token == 'NOTPROVIDED':
return format_html("")
else:
return format_html("<input type='hidden' name='csrfmiddlewaretoken' value='{}' />", csrf_token)
else:
# It's very probable that the token is missing because of
# misconfiguration, so we raise a warning
if settings.DEBUG:
warnings.warn(
"A {% csrf_token %} was used in a template, but the context "
"did not provide the value. This is usually caused by not "
"using RequestContext."
)
return ''
In this point of the code I was only seeing an item within the context, with a zip_code key.
I opened up the main template file and realized that I was making a rookie mistake - this was my main template menu/index.html:
{% extends 'base.html' %}
{% block content %}
<div class="menu-order-meta zip_calendar">
<div class="ink-grid align-center">
<div class="column-group gutters half-vertical-padding medium">
{% include 'partials/menu/zip-code.html' with zip_code=zip_code only %}
</div>
</div>
</div>
{% endblock %}
I was including the form through a partial template and I was explicitly restricting the available context within that partial template - notice the with zip_code=zip_code only declaration - (and by doing so, implicitly turning the csrf_token context processor unavailable).
Maybe are you missing django.middleware.csrf.CsrfViewMiddleware in MIDDLEWARE_CLASSES ?
MIDDLEWARE_CLASSES = (
....
'django.middleware.csrf.CsrfViewMiddleware',
....
)