Altough my form to send an offer is correctly displayed and I have no error when submitting the offers, they are not saved in my database.
I know that by checking the admin site, no objects are saved.
But on the other hand, I already have written the code for the registration and users are saved in the database.
I suspect the ForeignKey relation between my 2 models as the culprit.
models.py
from django.db import models
class User(models.Model):
username = models.CharField(max_length=30, unique=True, blank=False)
password1 = models.CharField(max_length=40, blank=False)
password2 = models.CharField(max_length=40, blank=False)
mail = models.EmailField(unique=True, blank=False)
birthday = models.DateField(blank=False)
date = models.DateTimeField(auto_now_add=True, auto_now=False, verbose_name="Date d'inscription")
def __str__(self):
return self.username
class Offer(models.Model):
publisher = models.ForeignKey(User)
content = models.TextField()
date = models.DateTimeField(auto_now_add=True, auto_now=False, verbose_name="Date de parution")
def __str__(self):
return self.publisher.username
forms.py
from django import forms
from django.contrib import admin
from django.contrib.auth.hashers import make_password, check_password
from django.utils.translation import ugettext_lazy as _
from myuser.models import User, Offer
class UserCreationForm(forms.ModelForm):
class Meta:
model = User
widgets = {
'password1' : forms.PasswordInput(),
'password2' : forms.PasswordInput(),
}
fields = ("username", "password1", "password2", "mail")
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("les mots de passes ne correspondent pas")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
user.password1 = make_password(self.cleaned_data["password1"])
user.password2 = make_password(self.cleaned_data["password2"])
if commit:
user.save()
return user
class LoginForm(forms.Form):
username = forms.CharField(label="nom d'utilisateur")
password = forms.CharField(label="mot de passe",
widget = forms.PasswordInput)
def clean(self):
cleaned_data = super(LoginForm, self).clean()
username = cleaned_data.get('username')
password = cleaned_data.get('password')
user = User.objects.get(username=username)
if check_password(password, user.password1):
return cleaned_data
else:
raise forms.ValidationError("Le nom d'utilisateur et le mot de passe ne correspondent pas")
class SendOfferForm(forms.ModelForm):
class Meta:
model = Offer
fields = ('content',)
Views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect, HttpResponse
from django.core.exceptions import ObjectDoesNotExist
from myuser.models import User, Offer
from myuser.forms import UserCreationForm, LoginForm, SendOfferForm
def get_logged_user_from_request(request):
if 'logged_user_id' in request.session:
logged_user_id = request.session['logged_user_id']
return User.objects.get(id=logged_user_id)
else:
return None
def register(request):
registered = False
if request.method == 'POST':
user_form = UserCreationForm(data=request.POST)
if user_form.is_valid():
user = user_form.save()
registered = True
else:
print(user_form.errors)
else:
user_form = UserCreationForm()
return render(request,
'myuser/create_account.html',
{'user_form': user_form, 'registered': registered} )
def login(request):
if request.method=='POST':
form = LoginForm(request.POST)
try:
if form.is_valid():
user = User.objects.get(username=request.POST.get('username'))
logged_user = User.objects.get(username=request.POST.get('username'))
request.session['logged_user_id'] = logged_user.id
return HttpResponseRedirect('/')
else:
error = "le nom d'utilisateur et le mot de passe ne correspondent pas"
return HttpResponse("Invalid login details supplied.")
except User.DoesNotExist:
return HttpResponse("Invalid login details supplied.")
else:
form = LoginForm
return render(request, 'myuser/mylogin.html', locals())
def send_offer(request):
sent = False
logged_user = get_logged_user_from_request(request)
if logged_user:
if request.method == 'POST':
try:
offerform = SendOfferForm(request.POST, instance=logged_user)
if offerform.is_valid():
sent = True
offerform.save()
else:
print(offerform.errors)
except:
return HttpResponse("drapeau except")
else:
offerform = SendOfferForm(instance=logged_user)
else:
return HttpResponse("Vous n'ĂȘtes pas connectĂ©")
return render(request, 'myuser/send_offer.html', locals())
urls.py
from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView
urlpatterns = patterns('myuser.views',
url(r'^inscription/$', 'register', name='create_account'),
url(r'^connexion/$', 'login', name='login'),
url(r'^envoyer_une_offre$', 'send_offer', name='send_offer'),
)
send_offer.html
{% extends "base.html" %}
{% block content %}
<h1> Offer </h1>
{% if not sent %}
<p> write your offer <p/>
<form action="{% url "send_offer" %}" method='POST' class='sendofferform'>
{{ form.errors }}
{{ form.non_field_errors }}
{% csrf_token %}
{{ offerform.as_p }}
<input type="submit" value="Submit" />
</form>
{% else %}
Offer is published
publish another offer?<br />
get back to the homepage<br />
{% endif %}
{% endblock %}
admin.py
from django.contrib import admin
from myuser.models import User, Offer#, Message
class UserAdmin(admin.ModelAdmin):
list_display = ('id', 'username', 'status', 'college', 'apercu_description')
list_filter = ('id', 'username', 'birthday')
date_hierarchy = 'date'
ordering = ('date', )
search_fields = ('username', 'description')
def apercu_description(self, User):
text = User.description[0:40]
if len(User.description) > 40:
return '%s' % text
else:
return text
class OfferAdmin(admin.ModelAdmin):
list_display = ('id', 'publisher', 'apercu_offre')
list_filter = ('id', )
date_hierarchy = 'date'
ordering = ('date', )
search_fields = ('publisher',)
def apercu_offre(self, Offer):
text = Offer.content[0:40]
if len(Offer.content) > 40:
return '%s' % text
else:
return text
admin.site.register(User, UserAdmin)
admin.site.register(Offer, OfferAdmin)
All of the other function works (register and login) and the register() function correctly saves the user but the send_offer() function, which is very similar to the register function doesn't work and after searching on internet for hours, I still have no idea why the offers are not saved.
But when I try to add an offer in the admin site, it seems to work.
Besides, I tried to save an offer in the python manage.py shell :
>>> Offer.publisher = "a"
>>> Offer.content = "lalalala"
>>> Offer.save()
Traceback (most recent call last):
File "/usr/local/lib/python3.4/dist-packages/django/core/management/commands/shell.py", line 69, in handle
self.run_shell(shell=options['interface'])
File "/usr/local/lib/python3.4/dist-packages/django/core/management/commands/shell.py", line 61, in run_shell
raise ImportError
ImportError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.4/code.py", line 90, in runcode
exec(code, self.locals)
File "<console>", line 1, in <module>
TypeError: save() missing 1 required positional argument: 'self'
EDIT : The solution was to add these lines :
if offerform.is_valid():
sent = True
offer = offerform.save(commit=False)
offer.publisher = User.objects.get(id=logged_user.id)
offer.save()
Please, note that logged_user is a function, which is described in view.py.
On a ModelForm if you don't pass any object when its instantiated It will create a new object in the database of the specified type. So in this case on your SendOfferForm you have specified Offer. IF you do pass an existing object it has to be the specified type in this case Offer.
It looks like you are trying to automatically fill the publisher field with the currently logged in user. In order to do this you need to manually set the publisher field to an instance of User.
If you intend for the form to create a new Offer in the database do this
offerform = SendOfferForm(request.POST)
If you are trying to update a current offer THEN you would need to pass an instance object into the form
offerform = SendOfferForm(request.POST, instance=someOffer)
To manually add the user field call save on your form with commit=False this will return an offer object WITHOUT saving to the DB. At this point you have a chance to customize the data in object and then save.
offer = offerform.save(commit=False)
offer.publisher = request.user.id
offer.save()
All of this is explained in more detail in the django documentation
ModelForm documentation
Related
Hi I have written a def clean(self) function in forms to make sure that if there was previously already a post with the same title, they will return a message saying that the title already exists and hence the form cannot be submitted.
Problem now:
When I enter a title that already exists and I try to create the post, all data previously input will be removed and I will be redirected to a fresh form. No errors were raised. What I want is for the error to be raised and shown to the user when I try to click on the create button so all data remains there and the user knows and can change the title before attempting the create the blog post again.
return cleaned_data in forms.py is not defined too...giving a nameerror
Guideline:
Note! There is NO slug field in my form. The slug is only for the url for each individual blogpost. But basically the slug consists of the title. Eg if my username is hello and my chief_title is bye, my slug will be hello-bye. Both the slug and the title has to be unique as you can see in the model, but there is no slug in the form.
models.py
class BlogPost(models.Model):
chief_title = models.CharField(max_length=50, null=False, blank=False, unique=True)
brief_description = models.TextField(max_length=300, null=False, blank=False)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
views.py
def create_blog_view(request):
context = {}
user = request.user
if not user.is_authenticated:
return redirect('must_authenticate')
if request.method == 'POST':
form = CreateBlogPostForm(request.POST or None, request.FILES or None)
if form.is_valid():
obj= form.save(commit = False)
author = Account.objects.filter(email=user.email).first()
obj.author = author
obj.save()
obj.members.add(request.user)
context['success_message'] = "Updated"
return redirect('HomeFeed:main')
else:
form = CreateBlogPostForm()
context['form'] = form
return render(request, "HomeFeed/create_blog.html", {})
forms.py
class CreateBlogPostForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['chief_title']
def clean(self):
chief_title = self.cleaned_data['chief_title']
qs = BlogPost.objects.filter(chief_title=chief_title)
if qs.exists():
raise forms.ValidationError('Post already exists')
return cleaned_data
html
<form class="create-form" method="post" enctype="multipart/form-data">{% csrf_token %}
{% if form.non_field_errors %}
{{form.non_field_errors}}
{% endif %}
<!-- chief_title -->
<div class="form-group">
<label for="id_title">Chief Title!</label>
<input class="form-control" type="text" name="chief_title" id="id_title" placeholder="Title" required autofocus>
</div> {{form.chief_title.errors}}
<button class="submit-button btn btn-lg btn-primary btn-block" type="submit">CREATE</button>
</form>
Well you can create a custom validator to check if the slug exists:
from django.core.exceptions import ValidationError
def validate_slug_exists(value):
blog_post = BlogPost.objects.filter(slug=value)
if blog_post.exists():
raise ValidationError('The post with a given title already exists')
Then in your form add this validator to the fields validators list:
class CreateBlogPostForm(forms.ModelForm):
chief_title = forms.CharField(validators = [validate_slug_exists])
UPDATE
You can also try using validate_unique() in your form class:
def validate_unique(self, exclude=None):
qs = BlogPost.objects.all()
if qs.filter(chief_title=self.chief_title).exists():
raise ValidationError("Blog post with this title already exists")
You can raise a ValidationError as shown in the docs. This would then be displayed in the form for the user.
def clean_slug(self):
slug = slugify(self.cleaned_data.get("chief_title")) if len(self.cleaned_data.get("slug", )) == 0 \
else self.cleaned_data.get("slug", )
if BlogPost.objects.filter(slug=slug).exists():
raise ValidationError(_('Slug already exists.'), code='invalid')
return slug
If you set unique = True Django takes care of checking whether another entry already exists in the database and adds an error in ModelForm.errors.
This is happening inModelForm.validate_unique.
There is no need to bother with this method unless you want to add more info in the error, such as the url of the existing object (it will cost 1 db hit).
Otherwise, the error already exists and you can just return the form with its errors instead of returning a new instance of the form as you currently do in views.py.
Therefore the following views.py as explained in this post should do what you are trying to do:
app/views.py:
def create_blog_view(request):
context = {}
# ...
if request.method == 'POST':
form = CreateBlogPostForm(request.POST or None, request.FILES or None)
if form.is_valid():
# do your thing
else:
context['form'] = form
return render(request, "HomeFeed/create_blog.html", context) # context instead of {}
If you want to get fancier and hit the db once more, you can add the url of the existing object in the errors list as such:
project/settings.py
...
# If you want to provide more info
MY_UNIQUE_BLOGPOST_ERROR_MESSAGE = "This BlogPost already exists"
...
app/models.py
from django.db import models
from django.conf import settings
from django.urls import reverse
class BlogPost(models.Model):
# ...
slug = models.SlugField(
blank=True,
unique=True,
error_messages={"unique": settings.MY_UNIQUE_BLOGPOST_ERROR_MESSAGE),
)
def get_admin_url(self):
return reverse("admin:app_blogpost_change", args=(self.id,))
...
app/forms.py
from django import forms
from django.conf import settings
from django.utils.html import format_html
from itertools import chain
from app.models import BlogPost
class CreateBlogPostForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = '__all__'
def validate_unique(self):
'''
If unique error exists, find the relevant object and return its url.
1 db hit
There is no other need to override this method.
'''
super().validate_unique()
if settings.SHOP_ENTITY_UNIQUE_ERROR in chain.from_iterable(
self.errors.values()
):
instance = BlogPost.objects.get(slug=self.instance.slug)
admin_url = instance.get_admin_url()
instance_name = instance.__str__()
self.add_error(
None,
forms.ValidationError(
format_html(
"This entry already exists: {1}",
admin_url,
instance_name,
),
code="unique",
),
)
My view:
'''
from django.shortcuts import render
from django.http import HttpResponse
from .models import Post
from .forms import createPostForm
def showPosts(request):
if request.method == "POST":
crf = createPostForm(request.POST)
crf.author = request.user
crf.save()
else:
crf = createPostForm()
context = {
'post' : Post.objects.all(),
'crf' : crf
}
return render(request, 'Content/FeedsPage.html', context)
'''
My Model:
'''
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
# image = models.ImageField(blank=True, null=True, upload_to='post_images/')
# video = models.FileField(blank=True, null=True, upload_to='post_videos/')
title = models.CharField(max_length=100)
description = models.CharField(blank=True, max_length=1000)
date_posted = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
'''
My Template:
'''
<form enctype="multipart/form-data" novalidate method="post">
{%csrf_token%}
<div class="fieldWrapper">
{{crf.title.errors}}
{{crf.title}}
</div>
<div class="fieldWrapper">
{{crf.description.errors}}
{{crf.description}}
</div>
<button class="primaryButton" type="submit">submit</button>
</form>
'''
My Form:
'''
from django import forms
from .models import Post
class createPostForm(forms.ModelForm):
title = forms.CharField(
widget = forms.TextInput(attrs={
'placeholder': 'Give a sweet title',
'autocomplete' :'off'
})
)
description = forms.CharField(widget=forms.TextInput(attrs={
'placeholder': 'Please elaborate a little',
'autocomplete' :'off'
}))
class Meta:
model = Post
fields = '__all__'
'''
I removed the is_valid() function to see whats happening and apperently its showing
'The Post could not be created because the data didn't validate'
Please somebody help
This save() method accepts an optional commit keyword argument, which accepts either True or False. If you call save() with commit=False, then it will return an object that hasn't yet been saved to the database. Which is neat for some post processing before actually saving it! So, you method should look something like this.
def showPosts(request):
if request.method == "POST":
crf = createPostForm(request.POST)
if crf.is_valid():
form = crf.save(commit=False)
form.author = request.user
form.save()
else:
crf = createPostForm()
context = {
'post' : Post.objects.all(),
'crf' : crf
}
return render(request, 'Content/FeedsPage.html', context)
I'm creating a staff registration page to create a new user (where NO one has logged in i.e. an Anonymous User). I have a Profile model (adding additional fields such as department, alias etc) which extends from the User model within Django. I've referenced User as a one-to-one relationship to Profile.
When a new staff registers, they have to specify their "stafftypeid" ("Job Title") from the ModelChoiceField referencing Staff_Type table. The User table doesn't store "stafftypeid", so I extended the UserCreationForm.
My problem is that I can successfully submit POST variables via the forms and the User (auth_user) will create a new record. I can see the new User within the Django /admin page. However, Profile will fail to create an accompanying new record and I receive an error ("IntegrityError at /register/
(1048, "Column 'staffTypeID' cannot be null")"). Strangely, I have all the POST variables, but the variables needed for the fields in Profile table are not being passed across.
Is this an inheritance problem? A new Profile record should only be created when you create a new User.
I've tried to follow tutorials and other code from Corey Schafer Django Tutorial 8, Simpleisbetterthancomplex (https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#onetoone) and Stack Overflow.
I've also tried re-writing def form.save() and then split my forms into two (originally just one), since its supposed to be easier to handle on the database side. I'd be really grateful for advice here!
Administrator\models.py: (Staff_Type)
from django.db import models
from decimal import Decimal
class Staff_Type(models.Model):
stafftypeid = models.AutoField(db_column='staffTypeID', primary_key=True)
stafftypedesc = models.CharField(db_column='staffTypeDesc', max_length=150)
class Meta:
ordering = ['stafftypedesc']
unique_together = ('stafftypedesc',)
db_table = 'stafftype'
def __str__(self):
return self.stafftypedesc
Users\models.py:
from django.db import models
from django.contrib.auth.models import User
from decimal import Decimal
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
stafftypeid = models.ForeignKey('Administrator.Staff_Type', models.DO_NOTHING, db_column='staffTypeID')
employeeid = models.CharField(max_length=20)
alias = models.CharField(max_length=20)
department = models.CharField(max_length=150)
organization = models.CharField(max_length=150)
fte = models.DecimalField(max_digits=4, decimal_places=1, default=Decimal(100.0))
def __str__(self):
return f'{self.user.username} Profile'
Users\signals.py:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
Users\register.html:
{% extends "Administrator/adminBase.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-md-8">
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Register New User </legend>
{{ user_form|crispy }}
{{ profile_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign Up</button>
</div>
</form>
</div>
</div>
{% endblock content %}
Users\forms.py:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from Administrator.models import Staff_Type
from .models import Profile
from .models import Profile
from django.utils.translation import ugettext_lazy as _
class UserRegisterForm(UserCreationForm):
email = forms.EmailField(max_length=150, label = "Email")
first_name = forms.CharField(max_length=150, label = "First Name")
last_name = forms.CharField(max_length=150, label = "Surname")
class Meta:
model = User
fields = ['username', 'email', 'first_name', 'last_name', 'password1', 'password2']
class ProfileForm(forms.ModelForm):
stafftypeid = forms.ModelChoiceField(queryset=Staff_Type.objects.all(), empty_label="Staff Type")
employeeid = forms.CharField(max_length=20, label="Employee ID")
alias = forms.CharField(max_length=20, label="Alias")
department = forms.CharField(max_length=150, label="Department")
organization = forms.CharField(max_length=150, label="Organization")
fte = forms.DecimalField(max_digits=4, decimal_places=1, min_value=0.0, max_value=100.0, label="FTE(%)")
class Meta:
model = Profile
fields = ['stafftypeid', 'employeeid', 'alias', 'department', 'organization', 'fte']
Users\views.py:
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm, ProfileForm
def register(request):
if request.method == "POST":
user_form = UserRegisterForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
username = user_form.cleaned_data.get('username')
stafftypeid = profile_form.cleaned_data.get('stafftypeid')
messages.success(request, f'Account created for {username}, with alias: {stafftypeid}')
return redirect('admin-home')
else:
user_form = UserRegisterForm()
profile_form = ProfileForm()
return render(request, 'users/register.html', {'user_form': user_form, 'profile_form': profile_form})
Users\apps.py:
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals
The error is happening in your signal. There you just create a Profile and only set the user field, you don't set any of the other fields.
You don't need this signal. You are creating the profile in the separate Profile form and saving it in the view. You should remove both those signals.
Then, update the view:
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
(Separately, please stop naming your ForeignKeys as ending in "_id"; they're not IDs, they are the actual related objects.)
I have a small problem with adding data to the database in django 2.0.3
I created the following model:
from django.contrib.auth.models import User
class UserInputSignal(models.Model):
name = models.CharField(max_length=512)
author = models.ForeignKey(User, on_delete=models.CASCADE)
input_file = models.FileField(upload_to='signals/', null=True)
I tried to solve the problem using this form:
from django import forms
from .models import UserInputSignal
class UserInputSignalForm(forms.ModelForm):
name = forms.CharField()
input_file = forms.FileField()
class Meta:
model = UserInputSignal
fields = ('name', 'input_file', )
and this view:
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate
from .forms import UserInputSignalForm
#login_required
def storage(request):
form = UserInputSignalForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
name = request.POST.get('name')
author = request.POST.get(request.user)
input_file = request.POST.get('input_file')
return redirect('home')
else:
form = UserInputSignalForm()
return render(request, 'storage.html', {'form': form})
In the template I called, I created the form as follows:
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
I am able to load a page with a form, but it does not post data to the database. I would like to add that I am a novice in django and some mechanisms are just plain understandable for me. Can I ask someone for help with this problem?
Before the redirect, call form.save()
Okay, i worked on your code and it works with me with slight modifications:
models.py
class UserInputSignal(models.Model):
name = models.CharField(max_length=512)
author = models.ForeignKey(User, on_delete=models.CASCADE)
input_file = models.FileField(upload_to='signals/', null=True)
objects = models.Manager()
#this returns the name for your modelobject
def __str__(self):
return self.name
forms.py
#excluded the assiging as fields defination is enough in itself
class UserInputSignalForm(forms.ModelForm):
class Meta:
model = UserInputSignal
#this will exclude the formfield it self but the author will be saved as the person who is logged in
exclude = ["author"]
Edited - Views.py
#login_required
def storage(request):
#authentication for author field using request.user
insta = UserInputSignal(author=request.user)
print(request.user)
form = UserInputSignalForm(request.POST or None, request.FILES or None,instance=insta)
if request.method == 'POST':
if form.is_valid():
signal = form.save(commit=False)
signal.save()
return redirect('home')
else:
form = UserInputSignalForm(instance=insta)
return render(request, 'storage.html', {'form': form})
JlucasRs was right to tell you to use form.save(), but you needed to assign form to something and need not use model fields here as forms.py does that for you.
app/Urls.py - Just for reference
urlpatterns = [
path('home/', home, name='home'),
path('storage/', storage, name='storage'),
]
Edit- Admin.py
from .models import PostModel, UserInputSignal
class UserInputSignalAdmin(admin.ModelAdmin):
list_display = ('name', 'author', 'input_file' )
admin.site.register(UserInputSignal, UserInputSignalAdmin)
Add this code in Admin.py if its not there.
I'm trying to ask a user some additional info while signing up. I'm using django allauth for authorization and authentication. I try to add three more fields during the signup process. If If I run it, it shows me the standard form plus gender field. However, it doesn't seem to really work. How can I save the data? Could someone help? Thank you in advance!
EDITED: if I just use
if form.is_valid():
form.save()
return redirect('/success/')
I get an error:
save() missing 1 required positional argument: 'user'
I'm quite new to django.
I created signups app in the project.
I put this in allauth_settings.py:
ACCOUNT_SIGNUP_FORM_CLASS = 'signups.forms.MySignupForm'
My signups/model.py:
from django.contrib.auth.models import User
from django.db import models
from allauth.account.models import EmailAddress
from allauth.socialaccount.models import SocialAccount
import hashlib
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
about_me = models.TextField(null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add= True, auto_now=False)
updated = models.DateTimeField(auto_now_add= False, auto_now=True)
GENDER_CHOICES = (
('m', 'Male'),
('f', 'Female'),
)
# gender can take only one of the GENDER_CHOICES options
gender = models.CharField(max_length=1, choices=GENDER_CHOICES,
verbose_name='Gender')
def __unicode__(self):
return self.user.username
class Meta:
db_table = 'user_profile'
def profile_image_url(self):
"""
Return the URL for the user's Facebook icon if the user is logged in via
Facebook, otherwise return the user's Gravatar URL
"""
fb_uid = SocialAccount.objects.filter(user_id=self.user.id, provider='facebook')
if len(fb_uid):
return "http://graph.facebook.com/{}/picture?width=40&height=40".format(fb_uid[0].uid)
return "http://www.gravatar.com/avatar/{}?s=40".format(hashlib.md5(self.user.email).hexdigest())
def account_verified(self):
"""
If the user is logged in and has verified hisser email address, return True,
otherwise return False
"""
if self.user.is_authenticated:
result = EmailAddress.objects.filter(email=self.user.email)
if len(result):
return result[0].verified
return False
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
my signups/forms.py:
from allauth.account.forms import SignupForm
from django import forms
from .models import UserProfile
class MySignupForm(SignupForm):
class Meta:
model = UserProfile
gender = forms.CharField(max_length=1, label='gender')
def save(self, user):
user.gender = self.cleaned_data['gender']
user.save()
my signups/views.py:
from django.template import RequestContext
from django.shortcuts import render_to_response
from .forms import SignupForm
def index(request):
form = MySignupForm(request.POST or None)
if form.is_valid:
???
return render_to_response("signups/index.html", locals(),
context_instance=RequestContext(request))
My index.html is very basic, I just wanted to see the representation of the form:
{% extends 'account/base.html' %}
{% block head_title %}ProjectName{% endblock %}
{% block content %}
<form method="POST" action="">
{{ form.as_p }}
<input type="submit">
</form>
{% endblock %}
You are instantiating the SignupForm, which is the standard form but not your MySignupForm in the view. Change it like this:
def index(request):
form = MySignupForm()
return render_to_response("signups/index.html", locals(),
context_instance=RequestContext(request))