Save data in associative model using one query in django - python

I am working on registration module in django project. for registering user i am using auth_user table for extending this table i have created one more model Profile
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
start_date = models.DateField()
phone_number = models.CharField(max_length=12)
address = models.CharField(max_length=225)
subscription = models.BooleanField(default=False)
Profile table has been created successfully. Now what i want to do is when i submit the registration form, the fields related to Profile model within registration form should be inserted automatically after inserting fields related to auth_user model.
Means i don't want to first insert data in auth_user model and then after getting it's id again insert data in Profile table.
I want to insert complete record in one query. Is it possible ?

I think you can define a registration form and override the form save method to save the Profile when creating the User model. Sample code for your reference:
class RegistrationForm(forms.ModelForm):
start_date = forms.DateField()
phone_number = forms.CharField()
address = forms.CharField()
subscription = forms.BooleanField()
class Meta:
model = User
def save(self, commit=True):
instance = super(RegistrationForm, self).save(commit=commit)
profile = Profile(user=instance, start_date=self.cleaned_data['start_date'], phone_number=self.cleaned_data['phone_number'], address=self.cleaned_data['address'], subscription=self.cleaned_data['subscription'])
profile.save()
return instance
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save()
# do anything after user created
else:
raise Error('form validate failed')
else:
# handling the GET method

Related

How to automatically get user in django admin through form

I have a form in my django website where the user requests coins and the information is sent to the admin for me to process. I want to automatically get the user who filled the form without them doing it themselves.
Here's the model.py file:
class Requestpayment (models.Model):
username= models.ForeignKey(User, on_delete= models.CASCADE, null=True)
useremail= models.CharField(max_length=100)
accountmail= models.CharField(max_length=100)
accountphonenumber=models.CharField(max_length=15)
coinsrequested=models.ForeignKey(Requestamount, on_delete= models.SET_NULL, null=True)
created= models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.accountmail
the forms.py:
class Requestpaymentform (ModelForm):
class Meta:
model = Requestpayment
fields = '__all__'
and the views.py:
#login_required(login_url='login')
def redeemcoins (request):
form = Requestpaymentform
if request.method =='POST':
form = Requestpaymentform(request.POST)
if form.is_valid():
form = form.save(commit=False)
username = request.user
form.save()
return redirect ('home')
I am pretty sure something is wrong but i don't know what it is (I'm very new at django) anyway the form always shows all the users in the website for the current user to pick who they are.
redeem coins page
I also tried excluding that part of the form but it didn't work it just shows up empty in the admin.
thank you.
You need to assign it to the instance wrapped in the form, so:
#login_required(login_url='login')
def redeemcoins(request):
form = Requestpaymentform()
if request.method == 'POST':
form = Requestpaymentform(request.POST)
if form.is_valid():
form.instance.username = request.user
form.save()
return redirect('home')
# …
It makes more sense however to name this field user than username. In the model you can also make the username field non-editable, such that it does not appear in the form:
from django.conf import settings
class Requestpayment(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE
)
# …
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
When you use username= models.ForeignKey(User, on_delete= models.CASCADE, null=True), Django add a field named user_id in your database which allow django to find User object for Requestpayment.
You can use user_id field to add a User object in Requestpayment.
You don't need to pass username field in your fields list if you want to get user in view.
class Requestpaymentform (ModelForm):
class Meta:
model = Requestpayment
#fields = '__all__'
fields = ['useremail',
'accountmail',
'accountphonenumber',
'coinsrequested',
'created']
Now do this to get user in your view.
#login_required(login_url='login')
def redeemcoins(request):
form = Requestpaymentform()
if request.method == 'POST':
form = Requestpaymentform(request.POST)
if form.is_valid():
requestpayment = form.save(commit=False)
requestpayment.user_id = request.user.id
requestpayment.save()
return redirect('home')
And it's great to use user instead username because it's a User object and not a simple field.
Please for my English !!!

Create a new model in Django linked tothe User table

I'm new to Django and I've correctly created my first web app where I can register and login as an user. I'm using the standard from django.contrib.auth.models import User and UserCreationFormto manage this thing.
Now, I would like to create a new table in the database to add new fields to the user. I'm already using the standard one such as email, first name, second name, email, username, etc but I would like to extend it by adding the possibility to store the latest time the email has been changed and other info. All those info are not added via the form but are computed by the backend (for instance, every time I want to edit my email on my profile, the relative field on my new table, linked to my profile, change value)
To do that I have added on my models.py file the current code
from django.db import models
from django.contrib.auth.models import User
class UserAddInformation(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_time_email_change = models.TimeField('Last email changed', auto_now_add=True, blank=True)
def __str__(self):
return self.user.username
And on my admin.py
from django.contrib import admin
from .models import UserAddInformation
admin.site.register(UserAddInformation)
The form to edit the email and the view can be found below
forms.py
class EditUserForm(UserChangeForm):
password = None
email = forms.EmailField(widget=forms.EmailInput(attrs={
'class': 'form-control'
}))
class Meta:
model = User
# select the fields that you want to display
fields = ('email',)
views.py
#authenticated_user
def account_user(request):
if request.method == "POST":
form = EditUserForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
user_info_obj = UserAddInformation.objects.create(user=request.user,
last_time_email_change=datetime.now())
user_info_obj.save()
messages.success(request, "Edit Succesfully")
else:
pass
else:
form = EditUserForm()
return render(request, 'authenticate/account.html', {
'form_edit': form,
})
The issue is that, once I'm going to update the email via the form, I got an error UNIQUE constraint failed: members_useraddinformation.user_id
Using ForeignKey make it works but it create a new row in the table, with the same when I just want to update the first one
The edit process for the email works tho
What am I doing wrong?
It turned out that auto_now_add=True inherit editable=False generating the error. So changing my models.py with
class UserAddInformation(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_time_email_change = models.TimeField('Last email changed')
def save(self, *args, **kwargs):
self.last_time_email_change = timezone.now()
return super(UserAddInformation, self).save(*args, **kwargs)
def __str__(self):
return self.user.username
and checking with
user_info_obj = UserAddInformation.objects.get_or_create(user=request.user)
user_info_obj[0].save()
inside def account_user(request): worked
I'm not sure it's the best solution for my issue tho

Can't update user profile in my Django app Django

I have created a Edit Profile form in my Django app but it doesn't save in the database.
This is the profile model:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', primary_key=True) #Each User is related to only one User Profile
city_search_text = models.CharField(blank=True, max_length=300)#user picks a city from autocomplete and in the view I get or create a City object
city = models.ForeignKey(City, blank=True, null=True, related_name='city') #Each User Profile must be related to one city.
prof_pic = models.ImageField(blank=True, upload_to='profile_pictures')
dob = models.DateField(blank=True, null=True)
def __str__(self):
return self.user.first_name
This is the form:
class EditProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('dob',)#I'm testing to update this field only
def save(self, commit=True):
profile = super(EditProfileForm, self).save(commit=False)
if commit:
profile.save()
return profile
This is the view:
def editprofile(request):
if request.method == 'POST':
edit_profile_form = EditProfileForm(request.POST, instance=request.user)
if edit_profile_form.is_valid():
profile = edit_profile_form.save(commit=False)
profile.save()
if 'next' in request.GET:
return redirect(request.GET['next'])
else:
print (profile_form.errors)
else:
edit_profile_form = EditProfileForm(instance=request.user.profile)
return render(request, 'excurj/editprofile.html', {'edit_profile_form':edit_profile_form,})
After I submit the form it forwards me to index page okay but the values remain the same in the user's profile.
Seems like
if edit_profile_form.is_valid():
isn't getting called at all, and your data is not saved. That means your form has invalid data, and you should check for form errors to detect those.
Also, you are trying to print form errors if the request isn't POST, which makes no sense and won't help you printing form errors. Try using this way;
if edit_profile_form.is_valid():
profile = edit_profile_form.save(commit=False)
profile.save()
else:
print (profile_form.errors)
And check your form for errors.
I figured it out eventually. In the view I should have passed an instance of the profile not the User object. So it needs to be like this:
edit_profile_form = EditProfileForm(request.POST, instance=request.user.*profile*)

Integrity error with django user model

I'm working through https://bixly.com/blog/awesome-forms-django-crispy-forms/ , trying to set up a bootstrap 3 form using django crispy forms.
in app1/models.py, I have set up my model:
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import AbstractUser
from django import forms
class User(AbstractUser):
# Address
contact_name = models.CharField(max_length=50)
contact_address = models.CharField(max_length=50)
contact_email = models.CharField(max_length=50)
contact_phone = models.CharField(max_length=50)
......
app1/forms.py:
class UserForm(forms.ModelForm):
class Meta:
model = User # Your User model
fields = ['contact_name', 'contact_address', 'contact_email', 'contact_phone']
helper = FormHelper()
helper.form_method = 'POST'
helper.form_action = "/contact/"
helper.form_id = 'form' # SET THIS OR BOOTSTRAP JS AND VAL.JS WILL NOT WORK
helper.add_input(Submit('Submit', 'Submit', css_class='btn-primary'))
app1/views.py:
def contact(request):
django_query_dict = request.POST
message = django_query_dict.dict()
if request.method == 'POST':
print "im in contact "+str(message)
form = UserForm(request.POST)
if form.is_valid():
form.save()
else:
print('invalid')
I've been able to get it working for the first record (screenshot above). However because I'm using/extending the user model I'm running into problems with the built in user registration functionality. When I try to add a second record I get:
Exception Type: IntegrityError at /contact/
Exception Value: column username is not unique
Request information:
GET: No GET data
I can see that this is true because I am not getting data for username in the form, so a blank will be entered both the first and second record causing the integrity error the second time. How can I fix this. Should I even be using the built in user model?

Creating & Updating UserProfiles in Django

Django newbie here stumbling my way around the docs. I'm trying to create a user profile using Django's "UserProfiles", but I'm having a little trouble with figuring out the proper way to set the code based on Django docs.
Here's my code, based on the docs. (The create_user_profile is 100% from the docs).
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User)
location = models.CharField(max_length = 100)
website = models.CharField(max_length=50)
description = models.CharField(max_length=255)
fullName = models.CharField(max_length=50)
email = models.EmailField(max_length = 100, blank = False)
created = models.DateTimeField(auto_now_add=True)
private = models.BooleanField()
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
What's the -proper- way to set and save these fields?
For example, if I have both the User and UserProfile models in one form (in a registration form, for example), how would I first create, then update all of this, before finally saving?
how would I first create, then update all of this, before finally saving
These aren't separate steps. When you create or update a record in Django, you are saving it to the database.
For the registration form, I'd recommend you set it up as a ModelForm on User records, then specify the additional fields you want to save to the profile and save them separately in the save function, like so...
class RegistrationForm(forms.ModelForm):
location = forms.CharField(max_length=100)
# etc -- enter all the forms from UserProfile here
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', and other fields in User ]
def save(self, *args, **kwargs):
user = super(RegistrationForm, self).save(*args, **kwargs)
profile = UserProfile()
profile.user = user
profile.location = self.cleaned_data['location']
# and so on with the remaining fields
profile.save()
return profile
You could call profile.user.save() and after it profile.save() when you need to save data from registration form.

Categories