I want to update user info with UserChangeForm and things go pretty well except for the ManyToManyField. When I render the page I can see that all user informations are displayed in correct order of each field like user's username will be in the username field but it's blank in manytomanyfield.
#model.py
class Department(models.Model):
name = models.CharField(max_length=100)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('Email Address'), unique=True)
department = models.ManyToManyField(Department)
# some other fields
# forms.py
class EditUserForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ['email', 'department', ..]
widgets = {'department': forms.CheckboxSelectMultiple()}
# view.py
def home(request):
template_name = "app/home.html"
edit_form = EditUserForm(instance=request.user)
if request.method == "POST":
edit_form = EditUserForm(request.POST, instance=request.user)
if edit_form.is_valid():
edit_form.save()
return JsonResponse({'success': True}, status=200)
else:
return JsonResponse({'error': edit_form.errors}, status=400)
return render(request, template_name, {'edit_form': edit_form})
# template
<form action="{% url 'home' %}" method="POST">
<div class="row">
{{edit_form.email}}
{{edit_form.first_name}}
{% for department in edit_form.department %}
<h6 id="checkbox">{{department.tag}} {{department.choice_label}}</h6>
{% endfor %}
</div>
</form>
here is the picture
As you can see the names and email are displaying inside the form field but why all checkboxes are empty? (Checkbox fields are department)
If you just want to render the field you don't need a for loop. You can just use {{edit_form.department}}. In case you need to modify each input field in CheckboxSelectMultiple you should loop through edit_form.department.field.choices.
For example:
{% for choice, value in edit_form.department.field.choices %}
<input type="checkbox" name="{{choice.instance.value}}" value="{{choice.instance.pk}}" id="id_{{choice.instance.value}}">
{% endfor %}
Note that this will work only in django 3.0 and newer.
you need pass the value and the name in the input in your template
{% for value, name in edit_form.fields.department.choices %}
<input type="checkbox" name="{{name}}" value="{{value}}" id="{{name}}">
{% endfor %}
Related
I have created my own user model in Django:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
is_active = models.BooleanField(_('active'), default=False)
token_num = models.IntegerField(_('token count'), default=0)
money_num = models.IntegerField(_('money count'), default=0)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
So then i decided to do my own login view. Here it is:
def login(request):
if request.method == "POST":
form = LoginForm(request.POST)
email = request.POST.get('email')
password = request.POST.get('password')
user = authenticate(username=email, password=password)
if user is not None and user.is_active:
login(request, user)
return HttpResponseRedirect("/main/")
else:
form = LoginForm()
return render(request, 'registration/login.html', {'form': form})
Here is my LoginForm:
class LoginForm(forms.Form):
user_email = forms.EmailField(max_length=255)
password = forms.CharField(max_length=255)
class Meta:
model = User
fields = ('email', 'password')
And my login.html:
{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="display: none">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color:red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit">Login</button>
</form>
{% endblock %}
And here is my urls.py:
urlpatterns = [
url(r'^log/$', views.login)
]
So the problem is that when I enter all data at login page the user doesn't log in and I'm not redirected to the main page. The login page is reloading and that's all.
P.S I have already created 1 user with email and password. This user is_active is set to True (1)
I think that the problem is in your LoginForm.
It is not ModelForm, so you can remove the Meta class.
And your email field is called user_email but in the login view, you try to get email from the POST params.
Try to get the consistent name and you should be able to log in.
Your LoginForm has the field user_email but your code access email from request.POST; these need to be the same.
Note, you should probably check form.is_valid() and get the data from form.cleaned_data, rather than direct from the POST. Also note, your form is (correctly) not a ModelForm so the inner Meta class and its contents are irrelevant.
I am working on my first Django project.
But I get following errors:
edit_file template
<form method="POST" action="{% url 'edit_file' file.id %}">
{% csrf_token %}
{{ form.errors }}
{{ form.non_field_errors }}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
<div class="form-group row">
<label for="id_name" class="col-sm-3 col-form-label"> File Name </label>
<div class="col-sm-4">
{% render_field form.name|add_class:"form-control" %}
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">File Path</label>
<div class="col-sm-4">
{% render_field form.directory_path|add_class:"form-control" %}
</div>
</div>
<div class="form-group">
{% render_field form.script_code|add_class:"form-control" %}
<pre id="id_script_code" style="height: 40pc;">{{ form.script_code }}</pre>
</div>
<button type="submit" class="btn btn-success mr-2">Save Changes</button>
Back
</form>
Views.py
def edit_file(request, id):
instance = get_object_or_404(File, id=id)
if request.method == "POST":
form = EditFileForm(request.POST, instance=instance)
if form.is_valid():
print('Form validation => True')
form.save()
return HttpResponse('<h1> database updated! </h1>')
else:
print('Form validation => False')
file = File.objects.latest('id')
context = {'file': file, "form": form}
return render(request, 'edit_file.html', context)
else:
instance = get_object_or_404(File, id=id)
form = EditFileForm(request.POST or None, instance=instance)
file = File.objects.latest('id')
context = {'file': file, "form": form}
return render(request, 'edit_file.html', context)
forms.py
class EditFileForm(ModelForm):
# field_order = ['field_1', 'field_2']
class Meta:
print("forms.py 1")
model = File
fields = ('name', 'script_code', 'directory_path','version')
def clean(self):
print("forms.py 2")
cleaned_data = super(EditFileForm, self).clean()
name = cleaned_data.get('name')
print("cleaned data: ", cleaned_data)
Models:
Version id point to a version which contains multiple files.
class File(models.Model):
# Incrementing ID (created automatically)
name = models.CharField(max_length=40)
script_code = models.TextField() # max juiste manier?
directory_path = models.CharField(max_length=200)
version = models.ForeignKey('Version', on_delete=models.CASCADE)
class Meta(object):
db_table = 'file' # table name
class Version(models.Model):
# Incrementing ID (created automatically)
version_number = models.CharField(max_length=20)
pending_update = models.BooleanField(default=False)
creation_date = models.DateTimeField(auto_now_add=True, null=True, editable=False)
modification_date = models.DateTimeField(auto_now_add=True, null=True)
connecthor = models.ForeignKey('ConnecThor', on_delete=models.CASCADE)
def __str__(self):
return self.connecthor_id
The problem:
form.is_valid() keeps failing. My view returns one error.
*version: This field is required. But I don't know how to fix this. Users should only be able to update 3 of the 5 data fields. So there is no reason to show the PK or FK in the template.
You've included version in the list of fields in your form, but you aren't outputting it in the template so there is no means of providing it. Since the model field does not specify blank=True, it is a required field, hence the error.
If you don't want users to be able to modify this field, you should remove it from that list of fields under Meta.
You do not have version in your template. Your model field for version does not say it can have null values. Hence your form validation fails. Include it in your template or remove the field from EditFileForm class's Meta class in forms.py
I have created my first app in Django (1.10.5) / Python 3.4. I have a login page and a register page. Which is working fine.
I can create new user and login with that id. Now after the login I want user to fill a form with some information and click on submit. And the information should get stored in the database.
So I created a model first : Model.py
class UserInformation(models.Model):
firstName = models.CharField(max_length=128)
lastName = models.CharField(max_length=128)
institution = models.CharField(max_length=128)
institutionNumber = models.CharField(max_length=128)
cstaPI = models.CharField(max_length=128)
orchidNumber = models.CharField(max_length=128)
This has created a table in the DB.
forms.py
class UserInformationForm(ModelForm):
class Meta:
model = UserInformation
fields = '__all__'
views.py
def home(request):
form = UserInformationForm()
variables = { 'form': form, 'user': request.user }
return render(request,'home.html',variables)
home.html
{% extends "base.html" %}
{% block title %}Welcome to Django{% endblock %}
{% block head %}Welcome to Django{% endblock %}
{% block content %}
<p> Welcome {{ user.username }} !!! Logout<br /><br /> </p>
<form method="post" action=".">{% csrf_token %}
<table border="0">
{{ form.as_table }}
</table>
<input type="submit" value="Submit" style="position:absolute"/>
</form>
{% endblock %}
But when I click on submit button, It does not insert data into my table.
here is the answer, we need to use the request.POST
def home(request):
if request.method == 'POST':
form = UserInformationForm(request.POST)
form.save()
return HttpResponseRedirect('/home/')
else:
form = UserInformationForm()
variables = { 'form': form, 'user': request.user }
return render(request,'home.html',variables)
the first: you need add urls.py to you app
the second: you need to change your views.py to lool like this
`
info = UserInformation()
lastName = request.POST.get('lastName')
...
info.save()
`
I need your help.
I extending class User and add same field, than extending UserCreationForm, but form is not valid.
Code crash in if form.is_valid().
Please help, why my form is not correctly?
models.py
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profile')
nick_name = models.CharField(max_length=15)
My register form
forms.py
class MyRegisterForm(UserCreationForm):
print "OK!"
nick_name = forms.CharField(max_length=30, required=True, widget=forms.TextInput)
print "Ook"
class Meta:
model = UserProfile
def save(self, commit=True):
if not commit:
raise NotImplementedError("Can't create User and UserProfile without database save")
print "Saving..."
user = super(MyRegisterForm, self).save(commit=False)
user.nick_name = self.cleaned_data["nick_name"]
user_profile = UserProfile(user=user, nick_name=self.cleaned_data['nick_name'])
user_profile.save()
print "Saving complete"
return user, user_profile
Register function
views.py
def reg(request):
if request.method =='POST':
form = MyRegisterForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
print username
password1 = form.cleaned_data['password1']
print password1
password2 = form.cleaned_data['password2']
print password2
nick_name = form.cleaned_data['nick_name']
print nick_name
form.clean_username()
if password1 == password2:
new_user = form.save()
return render_to_response('registration/registration_complete.html')
else:
print "Password error"
return render_to_response('registration/registration_fail.html')
else:
print "FORM error" #ТУТ ВАЛИТСЯ :(
return render_to_response('registration/registration_fail.html')
else:
form = UserCreationForm() # An unbound form
return render_to_response('registration/registration_new_user.html', {
'form': form,
},context_instance=RequestContext(request))
In setting
settings.py
AUTH_PROFILE_MODULE = 'registration.UserProfile'
Registration template
registration_new_user.html
{% extends "base.html" %}
{% block content %}
<h1>Registration</h1>
<form action="registration" method="post">
{% if form.error_dict %}
<p class="error">Please fix the error.</p>
{% endif %}
{% if form.username.errors %}
{{ form.username.html_error_list }}
{% endif %}
<label for="id_username">Login:</label><br> {{ form.username }}<br>
{% if form.password1.errors %}
{{ form.password1.html_error_list }}
{% endif %}
<label for="id_password1">pass:</label><br> {{ form.password1 }}<br>
{% if form.password2.errors %}
{{ form.password2.html_error_list }}
{% endif %}
<label for="id_password2">pass(again):</label><br> {{ form.password2 }}<br>
{% if form.nick_name.errors %}
{{ form.nick_name.html_error_list }}
{% endif %}
<label for="id_nick_name">nick:</label><br> {{ form.nick_name }}<br>
<br>
<input type="submit" value="Reg" />
</form>
{% endblock %}
Well, you have several issues in your code. For instance, you override UserCreationForm with MyRegistrationForm and indeed you instantiate the latter when the request is a POST, but when is not, you pass the template a normal UserCreationForm.
You do have a user in your UserCreationForm because this is a ModelForm whose model is UserProfile and there you have defined a user field. So it makes perfect sense that the forms complaint about this when you create it with the POST.
I don't see a very clear solution here because your code is somewhat tricky but first of all, use the same form with both GET and POST request type so this line in your views
form = UserCreationForm() # An unbound form
Would change for this one:
form = MyRegistrationForm() # An unbound form
In the template it won't appear the field user because you don't include them but it is in the form. As you are creating a new user, that field should be set to non-required because no user will be associated with the UserProfile because you are creating the user. You can set it to non-required adding the parameter blank=True to the model:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profile', blank=True)
nick_name = models.CharField(max_length=15)
UPDATE:
This is the code for your base class UserCreationForm save method:
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
As you can see, this code assumes that the user has a set_password attribute, in order to fix this, you have to add a def set_password(self, raw_password) method to your UserProfile class. This error happens because the form base class is designed to be used with normal Django User class, any other error you may encounter like this you will probably solve it by adding the fields required to your UserProfile. This one solves like this:
class UserProfile:
...
def set_password(self, raw_password):
# whatever logic you need to set the password for your user or maybe
self.user.set_password(raw_password)
...
I hope this bring some light to the problem. Good luck!
I have this as template account_form.html
<form action="/contact/" method="post">
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Send message" /></p>
</form>
My model.py
class Account(models.Model):
person_name = models.CharField(max_length=30)
account_number = models.IntegerField()
creation_date = models.DateField()
My View is
def account_form(request):
if request.method == 'POST': # If the form has been submitted...
form = AccountForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = AccountForm() # An unbound form
return render_to_response('account_form.html', {
'form': form,
})
The problem is when i load the page i only get the submit button nothing else
I think you forgot to actually create your form:
Should read something like this:
forms.py:
from django.forms import ModelForm
from yourapp.models import Account
class AccountForm(ModelForm):
class Meta:
model = Order
This will give you all fields from Account.
HTH