Django - Allow User to Edit Profile and then Show Updated Profile fields - django-forms

I have the form populating with the user profile information, but when I click save, it doesn't actually update.
Any clues/hints as to which part I need to modify is greatly appreciated.
Thanks in advance!
views.py
def profile_view(request):
user = request.user
form = EditProfileForm(initial={'first_name':user.first_name, 'last_name':user.last_name})
context = {
"form": form
}
return render(request, 'profile.html', context)
def edit_profile(request):
user = request.user
form = EditProfileForm(request.POST or None, initial={'first_name':user.first_name, 'last_name':user.last_name})
if request.method == 'POST':
if form.is_valid():
user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
user.save()
return HttpResponseRedirect('%s'%(reverse('profile')))
context = {
"form": form
}
return render(request, "edit_profile.html", context)
forms.py
class EditProfileForm(forms.ModelForm):
first_name = forms.CharField(label='First Name')
last_name = forms.CharField(label='Last Name')
class Meta:
model = User
fields = ['first_name', 'last_name']
edit_profile.html
{% extends "base_site.html" %}
{% block content %}
<h1>Edit Profile</h1>
<form method="POST" action="/accounts/profile/" class="" />
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
{% endblock %}
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^register/$', 'accounts.views.registration_view', name='auth_register'),
url(r'^login/$', 'accounts.views.login_view', name='auth_login'),
url(r'^logout/$', 'accounts.views.logout_view', name='auth_logout'),
url(r'^profile/$', 'accounts.views.profile_view', name='profile'),
url(r'^profile/edit/$', 'accounts.views.edit_profile', name='edit_profile'),
]

The action in your form is POSTing to profile_view and not edit_profile and your forms are self closing so they aren't being POSTed correctly.
Change this:
<form method="POST" action="/accounts/profile/" class="" />
To this:
<form method="POST" action="/accounts/profile/edit" class="" >
Or even better, use the django url template tag:
<form method="POST" action="{% url 'edit_profile' %}" class="" >

Related

Summernote using Django forms displaying with HTML tags

Hi So I have just set up summernote for the first time, however when I save all the HTML tags are displayed in another page where I am displaying the text. I want it to display the correct way without the HTML, thanks for any help :)
FORMS.PY
from django_summernote.widgets import SummernoteWidget, SummernoteInplaceWidget
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title','content']
widgets = {
'content': SummernoteWidget(),
}
VIEWS.PY
class PostCreateView(CreateView):
model = Post
form_class = PostForm
Form HTML
<div class ='content-section'>
<form method="POST">
{% csrf_token %}
<fieldset class ="form-group">
<legend class ="border-bottom mb-4">Post 1</legend>
{{form|safe}}
</fieldset>
<div class="form-group">
<button class = "btn" type="submit">Post</button>
</div>
</form>
</div>
display Post HTML
{% extends 'guide/base.html' %}
{%block content%}
{% if post.author == user %}
Edit
Delete
{% endif %}
<div class = 'content'>
<h2>{{post.title}}</h2>
<p></p>
<p>{{ post.content }}</p>
</div>
{% endblock content %}
I didn't include the safe in the html so
{{post.content|safe}}
did not include because I thought you only include the safe in the form

Updating a SQL Alchemy list without reloading the page?

I am working on a small Flask app and the user is able to update a list of items via using a form to submit some data.
I am currently using SQL Alchemy as the ORM for my database and using the list in my template to display the items. I want to update it so that when the list is updated. The page is updated without the user having to reload the page.
I have tried this with AJAX using the below script but the update is not occurring.
$(document).ready(function(){
$('form').on('submit',function (e) {
$.ajax({
type: 'post',
url: '/todo',
data: $('#todoInput').serialize(),
success: function (q) {
console.log(q);
}
});
e.preventDefault();
});
}
My template:
{% extends "base.html" %}
{% block script %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="{{ url_for('static', filename='js/custom.js') }}"></script>
{% endblock %}
{% block content %}
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-success" role="alert">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
<div class="row justify-content-md-center">
<div class="col-md-auto">
<h1>What needs to be done today?</h1>
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-auto">
<form action="" method="post">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.todo (id="todoInput") }}
{{ form.submit (class_="btn btn-primary btn-sm") }}
</div>
</form>
<div id="todoList">
<ul class="list-group">
{% for todo in todos %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ todo.body }}
<button type="button" class="close" aria-label="Close"><span aria-hidden="true">×</span></button>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %}
Model:
from datetime import datetime
from app import db, login
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
todos = db.relationship('Todo', backref='owner', lazy='dynamic')
def __repr__(self):
return '<User {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
#login.user_loader
def load_user(id):
return User.query.get(int(id))
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Todo {}>'.format(self.body)
Route:
#app.route('/todo', methods=['GET', 'POST'])
def todo():
if current_user.is_authenticated:
form = TodoForm()
todos = current_user.todos.order_by(Todo.timestamp.desc()).all()
if form.validate_on_submit():
new_todo = Todo(body=form.todo.data, owner=current_user)
db.session.add(new_todo)
db.session.commit()
flash('Todo added')
todos = current_user.todos.order_by(Todo.timestamp.desc()).all()
return render_template('todo.html', form=form, todos=todos)
return render_template('todo.html', form=form, todos=todos)
flash('You first need to login or register')
return redirect(url_for('index'))
The todos list is what im trying to update. But it just reloads the page :/
You need to do two things. Firstly you need to be sure that your database is updated. That means that your form was submitted successfully. This can be done by submitting the form manually via an ajax call. This is more or less what you did. Did you check, whether your backend receives the form-submission and updates the database?
Secondly you need to update the html in the browser. Normally the page is refreshed automatically if your form is submitted. If you dont want a page reload, you need to add some client-side logic, to ensure that the page is updated. This can easily be done with a little bit of javascript.
Edit:
Your custom js might be missing }); at the end. Or did you just forget to post it here?

form.is_valid() is false when it shouldn't be

So i'm new in Django and i'm trying some tutorials. This code is exact same as the one in tutorial but it does not work form me.
views.py
from .forms import BlogPostForm
def blog_post_create_view(request):
form = BlogPostForm(request.POST or None)
if form.is_valid():
print(form.cleaned_data)
else:
print(form.slug, form.title, form.content)
template_name = "form.html"
context = {"form": None}
return render(request, template_name, context)
forms.py
from django import forms
class BlogPostForm(forms.Form):
title = forms.CharField()
slug = forms.SlugField()
content = forms.CharField(widget=forms.Textarea)
form.html
{% extends "base.html" %}
{% block content %}
{% if title %}
<h1> {{ title }}</h1>
{% endif %}
<form method="POST" action="."> {% csrf_token %}
{{ form.as_p }}
<button type="submit">SEND</button>
</form>
{%endblock%}
So when I run this, code the is_valid() functions returns False and I get :
AttributeError: 'BlogPostForm' object has no attribute 'slug'

Using django crispy form, how do you set extra_context in the Field method of the Layout object?

I am using crispy forms 1.6 with django 1.9 and python 3.4.
In using the Field class with a Layout , I am not able to get the extra_context to work. The values are not being injected into the context.
The template below fails to output the "threshold" value.
Here is my form code.
# project_edit_form.py
from django import forms
from django.contrib.auth.models import Group
from .models import Projects
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, HTML
class ProjectEditForm(forms.ModelForm):
class Meta:
model = Projects
fields = ('project_description', 'location', 'days_elapsed',)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
# ...
self.helper.layout = Layout(
Fieldset(
'Project',
'project_description',
'location',
Field('days_pge_first_responded', template="days_elapsed_field.html", extra_context={"threshold":15})%}"),
),
)
super(ProjectEditForm, self).__init__(*args, **kwargs)
And here is the html template for the Field:
# days_elapsed_field.html
extra_context.threshold: {{ extra_context.threshold }}
threshold: {{ threshold }}
field.threshold: {{ field.threshold }}
<div id="div_id_{{ field_name }}" class="form-group">
<label for="{{ field.id_for_label }}" class="control-label"> {{ field.label }} </label>
<div >
<input
style="{% if field.value > threshold %} background-color:#FFE8E8; {% else %} background-color:#e3e3e3 {% endif %}"
class="textinput textInput form-control" id="{{ field.id}}" name="{{ field.name}}" readonly="True" type="text" value="{{ field.value }}" />
</div>
</div>
And here is the main html template:
{% load crispy_forms_tags %}
<!doctype html>
<html>
<head>...</head>
<body>
<form action="" method="post" class="form-horizontal" >
{% crispy form %}
</form>
</body>
</html>
I couldn't figure out a built-in way of doing it, so I just created a generic class and used that instead. You can pass extra_context as a kwarg to CustomCrispyField. extra_context is just a dictionary that I access in my custom template that I copied from crispy_forms.
from crispy_forms.layout import Field
from crispy_forms.utils import TEMPLATE_PACK
class CustomCrispyField(Field):
extra_context = {}
def __init__(self, *args, **kwargs):
self.extra_context = kwargs.pop('extra_context', self.extra_context)
super(CustomCrispyField, self).__init__(*args, **kwargs)
def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, extra_context=None, **kwargs):
if self.extra_context:
extra_context = extra_context.update(self.extra_context) if extra_context else self.extra_context
return super(CustomCrispyField, self).render(form, form_style, context, template_pack, extra_context, **kwargs)
And I would use it like so in my form:
self.helper.layout=Div(CustomCrispyField('my_model_field', css_class="col-xs-3", template='general/custom.html', extra_context={'css_class_extra': 'value1', 'caption': 'value2'})
And my template would have code similar to the following:
{% crispy_field field %}
<button class="btn {{ css_class_extra }}">{{ caption }}</button>

Error while passing a POST data to form wizard

I have an initial form as below
forms.py
class LoginForm(forms.Form):
activity_no = forms.CharField()
username = forms.CharField()
views.py
def test(request):
if request.method == 'POST' :
form = LoginForm(request.POST)
if form.is_valid() :
act_no = form.cleaned_data['activity_no']
username = form.cleaned_data['username']
form_data = {}
form_data['activity_no'] = act_no
form_data['username'] = username
return render_to_response("test1.html", { 'form_data' : form_data}, context_instance=RequestContext(request))
else:
form = LoginForm()
return render_to_response("test.html", {'form': form }, context_instance=RequestContext(request))
test.html
{% extends "admin/base.html" %}
{% block content %}
<form action="/todo/test/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
test1.html
{% extends "admin/base.html" %}
{% block content %}
<form action="/todo/login/" method="post">{% csrf_token %}
{% for name, data in form_data.items %}
<input type="hidden" name={{name}} value={{data}}>
{% endfor %}
<input type="submit" value="Yes"/>
</form>
{% endblock %}
I fill this form, display few contents of a file and pass the above form data to a form wizard
But when I pass the data to the form wizard via post method in the template, I get a "ManagementForm Data missing" error but if the data is passed through the GET method, I don't get any error but as defined, the data is seen in the url in the GET method ( in my case it contains username which I don't want to disclose)
My Form Wizard
class LoginWizard(SessionWizardView):
def __name__(self):
"""When using decorators, Django tries to get the name of the
function and since we're a class, we'll fail. So add this method to
compensate."""
return 'LoginWizard'
template_name = "wizard_form.html"
def done(self, form_list, **kwargs) :
form_data = process_form_data(form_list)
My query is that how would I handle the post data in the form wizard.
Please let me know if I am missing anything or any other information is required from my end.
You need to add {{ wizard.management_form }} in your template as explained it in reference django wizard templates.
Like:
{% extends "admin/base.html" %}
{% block content %}
<form action="/todo/test/" method="post">{% csrf_token %}
{{ wizard.management_form }}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
Add that in all templates for wizard.

Resources