I am using an extended user model from all-auth. I am able to pull both extended model fields (like organization), as well as the standard user fields (like user.email) easily on all templates except one.
Because I struggled to build an update form (as I'm still new to Django), I ended up using properties/instances. This worked. I can edit orgnization. But for some reason on this template I cannot call user.email. I've tried all variations of it, from RequestContext to failed attempts at passing it in other ways.
Model:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
organization = models.CharField(max_length=100)
def __str__(self):
return self.user.organization
# I got this from an old tutorial:
User.profile_p = property(lambda u: Profile.objects.get_or_create(user=u)[0])
View:
from django.shortcuts import render, render_to_response
from django.http import HttpResponseRedirect
from django.template.context_processors import csrf
from .forms import UserProfileForm
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from .models import Profile
#login_required
def user_profile(request):
if request.method == 'POST':
form = UserProfileForm(request.POST, instance=request.user.profile_p)
if form.is_valid():
form.save()
return HttpResponseRedirect('/base_home.html')
else:
logged_user = request.user
profile = logged_user.profile_p
form = UserProfileForm(instance=logged_user.profile_p)
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('profile.html', args)
Template:
{% extends 'base.html' %}
<title>{% block title %}Admul:{% endblock %}</title>
{% block content %}
<div id="cd_content">
<div class="container-fluid">
<div class="row-fluid">
<h3>Account Details for: {{ user.email }}</h3>
<div class="widget-box">
<div class="widget-content nopadding">
{% for field in form %}
{{field.error}}
{% endfor %}
<form method="post" action="/cust_profile/profile/">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Edit ยป</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
For some reason, user.email or many variations thereof (like {{request.user.email}} ) does not work in this template. It, however, works perfectly fine in all other templates. Is it something to do with my view cancelling the RequestContext info from being passed?
Also, thanks in advance if you see me making any other silly errors that can be fixed.
You should not be using render_to_response in your view. That does not run context processors, and so does not add the request or user variables. Use render instead:
return render(request, 'profile.html', args)
Also note that CSRF will be added by a context processor, so there is no need to add it manually as you are doing.
Related
I am a Django beginner and I started working on my first project. I implemented a model "extendedUser" with a medic_code field, extending User. It appears to be a problem when displaying the medic_code in a template. It doesn't display the actual property of the user, but the default value: "".
Template
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }} </p>
<p class="text-secondary">{{ user.medic_code }}</p> (empty string here)
</div>
</div>
<!-- FORM HERE -->
</div>
{% endblock content %}
models.py:
from django.db import models
from django.contrib.auth.models import User
class extendedUser(User):
medic_code = models.CharField(max_length=20, default='')
users/forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from users.models import extendedUser
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
medic_code = forms.CharField(max_length=20)
class Meta:
model = extendedUser
fields = ['username', 'email', 'medic_code', 'password1', 'password2']
views.py:
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
user = form.save()
#user.refresh_from_db()
user.medic_code = form.cleaned_data.get('medic_code')
user.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in! Your medic code {user.medic_code}') #correct value displayed here
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
#login_required
def profile(request):
user = request.user
return render(request, 'users/profile.html', {'user':user})
Also after I create a user and display the medic_code field in a Django shell for that user, the proper value is displayed. What may be problem?
Thanks!
I have a small Django project consisting of one app. I am very very new to Django and have run into a problem. I have an app that is a webpage with a question posed and a form that must have input. Once the button is pressed to submit the form, I would like to update the page without refreshing. I have heard AJAX is a good way to handle this but I have not been able to find any examples working with just forms.
UPDATE
after researching another users suggestions I have made some progress implementing ajax to display my form submission text. The problem is now that when navigating to the app page it displays just raw html. I am not sure why.
My Forms
from django import forms
from . import models
class AnswerForm(forms.Form):
answer = forms.CharField(label='Answer', required=True, max_length=500)
def save(self):
answer_instance = models.Answer()
answer_instance.answer_txt = self.cleaned_data["answer"]
answer_instance.save()
return answer_instance
My Models
from django.db import models
from django.forms import ModelForm
class Riddle(models.Model):
riddle_txt = models.CharField(max_length=900)
def __str__(self):
return self.riddle_txt
class Answer(models.Model):
answer_txt = models.CharField(max_length=900)
def __str__(self):
return self.answer_txt
My Views
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, render
from django.template import loader
from .models import Riddle, Answer
from . import forms
# Create your views here.
def index(request):
form = forms.AnswerForm()
response_data = {} #new line
if request.method == "POST":
form = forms.AnswerForm(request.POST)
if form.is_valid():
form.save()
form = forms.AnswerForm()
response_data['text'] = form.answer_txt #new line
else:
form = forms.AnswerForm()
riddle_list = Riddle.objects.all()
answer_list = Answer.objects.all()
form = forms.AnswerForm()
template = loader.get_template('CricksRiddles/index.html')
context = {
'riddle_list': riddle_list,
'form': form,
'answer_list': answer_list,
}
#form_answer = request.POST['_form']
return render(request, 'CricksRiddles/index.html', context, {'json_data': json.dumps(response_data)}) #new line
My JS
$('#answer_form').on('submit', function(e){
e.preventDefault();
console.log("form submitted");
post_answer();
});
function post_answer() {
console.log("answer is posted without refresh");
console.log($('#answer_text').val());
}
and finally here is
MY Templates
{% extends 'base.html' %}
{% load static %}
{% block content%}
<body>
{% if riddle_list %}
<div class="riddle_box">
{% for riddle in riddle_list %}
<!-- -->
<p>{{ riddle.riddle_txt }}</p>
{% endfor %}
<!--
<!--{% for ans in answer_list %}-->
<li>{{ ans.answer_txt }}</li>
<!--{% endfor %}-->
</div>
<form id="answer_form" action="/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="button" name="_form" value="Submit Answer">
</form>
{% else %}
<p>Out foraging for sticks and dogs.</p>
{% endif %}
</body>
{% endblock %}
{% block js_block %}
{% endblock %}
It's my understanding that the AJAX code would go in the block js_block, but again I can not find any information on using AJAX with a django form. Everything I have found has been model forms, but I do not want to use those. Thank you for any help.
I have a Django project in which trying to 'update' (clicking on the button) causes the following error:
CSRF verification failed. Request aborted.
Help
Reason given for failure:
CSRF token missing or incorrect.
I have viewed various questions and answers that suggest that adding RequestContext is the solution, but I have tried something to that effect tailored to my code, and still am unable to get it working.
Original code views.py is below
#USERS (register) view.py
from django.shortcuts import render,redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages #this allows us flash messages for testing
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm
from .forms import UserUpdateForm
from .forms import ProfileUpdateForm
from django.contrib.auth.decorators import login_required
def register(request):
if request.method =='POST':
#this UserRegisterForm is created in forms.py and inherits from UserCreationForm (the ready made form)
form = UserRegisterForm(request.POST) #create a form that has the data that was in request.POST
if form.is_valid(): #is the form valid (do you have a username like this already, passwords match?
form.save()
username = form.cleaned_data.get('username')
messages.success(request,f'Account created for {username}, you can now login.')
return redirect('login')
else:
form =UserRegisterForm() #if the form input is invalid, render the empty form again
return render(request, 'users/register.html',{'form':form})
#login_required #this is a decorator (adds functionality to an existing function)
def profile(request):
if request.method =='POST':
u_form =UserUpdateForm(request.POST,instance=request.user)
p_form =ProfileUpdateForm(request.POST, request.FILES,instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request,f'Your Account has been directed')
return redirect('profile')
else:
u_form =UserUpdateForm(instance=request.user)
p_form =ProfileUpdateForm(instance=request.user.profile)
context={
'u_form': u_form,
'p_form': p_form
}
return render(request,'users/profile.html',context)
As mentioned I also tried:
return render(request,'users/profile.html',context_instance=RequestContext(request))
I also tried adding the below to imports
from django.shortcuts import get_object_or_404, render,redirect
Note: I do not wish to try the 'remove middleware' alternative.
The profile.html file code is below and I have included the CSRF token correctly, as far as I know:
{% extends "socialmedia/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }}</p>
</div>
</div>
<form method="POST" enctype="multipart/form-data>
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Profile Information</legend>
{{u_form|crispy}}
{{p_form|crispy}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update....</button>
</div>
</form>
</div>
{% endblock content %}
Finally, for context, here is forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
class UserRegisterForm(UserCreationForm): #form that inherits from the usercreationform
email = forms.EmailField()
class Meta:
model = User
#when this form validates it creates a new user
#type the fields to be shown on your form, in that order.
fields = ['username','email','password1','password2']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username','email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model= Profile
fields=['image']
Question: What is causing the error and what do I need to add/change in the code as it stands?
I also came across an answer on StackOverflow which said this "The problem is you are not returning the result. Remember that the view is a function. You need to return render_to_response(...) not just call it (which is also why by removing CSRF you got the didn't return an HttpResponse error)" ....can someone explain this in my context? I don't understand what it means or how to implement it either.
It looks like it should work, however I noticed you seem to be missing a quote at the end here
<form method="POST" enctype="multipart/form-data>
Could you please help me with Django and custom user model? I'm a new in Django world, so I started to learn from newest version 1.7. In my project I'm using django-allauth package and I want to create OneToOne relationship between standard user class from contrib.auth and my custom model "users".
#models.py
import datetime
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user=models.OneToOneField(User)
f_name=models.CharField(null=True, blank=True, max_length='30')
l_name=models.CharField(null=True, blank=True, max_length='30')
birth_date=models.DateField(null=True, blank=True)
company=models.CharField(null=True, blank=True, max_length='30')
rate=models.FloatField(null=True, blank=True, default=0.0)
skills=models.CharField(null=True, blank=True, max_length='255')
bill_rate=models.CharField(null=True, blank=True, max_length='255')
contacts=models.CharField(null=True, blank=True, max_length='255')
portfolio=models.CharField(null=True, blank=True, max_length='127')
avatar = models.ImageField(upload_to='/static/img/%Y/%m/%d', blank=True, null=True)
def __unicode__(self):
return self.user.username
This is forms.py
#forms.py
from django.forms import ModelForm
from users.models import Profile
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ('f_name', 'l_name', 'company', )
This is a template:
{% extends "base_.html" %}
{% block main_content%}
<div>
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.id }}!</p>
<form id="profile_form" method="POST" action="/accounts/profile" enctype="multipart/form-data">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Save" />
</form>
{% endif %}
</div>
{% endblock%}
And views.py:
from django.http import HttpResponse
from django.template import RequestContext
from django.conf import settings
from django.shortcuts import render, render_to_response
from models import Profile
from forms import ProfileForm
def edit(request):
profile_form = ProfileForm()
user = request.user
if request.method == 'POST':
profile_form = ProfileForm(data=request.POST, instance=user)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return render_to_response("profile.html", RequestContext(request))
return render_to_response('profile_edit.html', RequestContext(request, {'profile_form' : profile_form}))
I built all of this files according by this tutorial:
http://www.tangowithdjango.com/book/chapters/login.html
And finally, all of this works fine, but when I push Save button, POST form doesn't work. I can't see any changes in database. Redirecting works good, actually it seems that all works fine, but I don't have any data in table (I'm using postgres by the way).
I spent a lot to find the answer and tried almost everything in the internet, but I still have this issue. Maybe I can't understand how it works from django documentation, but I tried the same method and still have a problem.
Thank you in advance!
UPDATE:
My urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
# Examples:
url(r'^$', 'laniakea.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^accounts/', include('allauth.urls')),
url('accounts/profile', 'laniakea.views.prof', name='prof'),
url(r'^edit', 'users.views.edit', name='edit'),
)
I found a solution! As Daniel said, I changed "action" attribute to transfer POST request to the same form. And as I discovered, I not created a right instance of User parent class. Actually, I don't need to use them.
#views.py
from django.template import RequestContext
from django.shortcuts import render
from models import Profile
from forms import ProfileForm
def edit(request):
user = request.user
if request.method == 'POST':
profile_form = ProfileForm(request.POST)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return HttpResponseRedirect('accounts/profile')
else:
profile_form = ProfileForm()
return render(request, 'profile_edit.html', {'profile_form' : profile_form})
and
#profile_edit.html
{% extends "base_.html" %}
{% block main_content%}
<div>
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.id }}!</p>
<form id="profile_form" method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Save" />
</form>
{% endif %}
</div>
{% endblock%}
Thank you very much for help and good luck!
Could you review my code for improvement? Essentially, it works but it isn't user friendly. For example,(1) If the user puts in an invalid field, it doesn't tell them what field is invalid. (2) If a user tries to register (sign up) with an existing username, there is no way the user can distinguishes that error, specifically. Or if a user mis-type password confirm, the user won't know that mistake either. (3) Also, if the user produces an input error(s), the sign up page blanks out all the field and so the user has to re-enter in all the info. As you can imagine, that could be very frustrating for that user.
I tried to see if form.error_messages might help the user, the error_messages is useless.
How would you improve the code so that (1), (2), (3) is not a nuisance for the user? And one more thing, just curious about how you would change the css? I noticed that most professional website sign-up page highlight the input box that was invalid. I am clueless on how to apply changes to css for {{form|as_bootstrap}}
Many thanks for your help!
form.py:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True,help_text="Email field is required.")
firstname = forms.CharField(max_length=50, required=False, help_text="Optional. Can fill in later.")
lastname = forms.CharField(max_length=50, required=False, help_text="Optional. Can fill in later.")
class Meta:
model = User
fields = (
'username',
'email',
'password1',
'password2',
'firstname',
'lastname'
)
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data["email"]
user.firstname = self.cleaned_data["firstname"]
user.lastname = self.cleaned_data["lastname"]
if commit:
user.save()
return user
views.py
from django.shortcuts import render, render_to_response
from django.http import HttpResponseRedirect
from django.contrib import auth
from django.core.context_processors import csrf
from forms import MyRegistrationForm
def register_user(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/account/register_success')
else:
form = MyRegistrationForm()
args = {}
args.update(csrf(request))
args['form']= form
print form.errors #this line doesn't print anything
return render_to_response('register.html', args)
else:
return HttpResponseRedirect('/')
def register_success(request):
return render_to_response('register_success.html')
register.html
{% extends 'base.html' %}
{% load bootstrap_toolkit %}
{
{% block title %}
<title>Register</title>
{% endblock %}
<body>
{% block content %}
<div class="col-sm-9 col-sm-offset-3 col-md-6 col-md-offset-2 main">
<h2>Register</h2>
{% if form.error_messages %}
<p class="error"> {{ form.error_messages }}.</p>
{% endif %}
<form class="form-signup" role="form" action="/account/register/" method="post"> {% csrf_token %}
{{ form|as_bootstrap }}
<input type="submit" value="Register" class="btn btn-primary"/>
</form>
</div>
{% endblock %}
</body>