Django hidden field is not saving to database - python

I am trying to save users IP address in my extended profile model. The goal is to make this a hidden field. Currently, I can debug by printing the IP address to the console. The issue arises when I try and save the info.
views.py
def index(request):
#request.session.flush()
if request.user.is_authenticated:
return redirect('ve:dashboard')
elif request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.refresh_from_db() # Load the profile instance created by the Signal
user.profile.birth_date = form.cleaned_data.get('birth_date')
user.ipaddress = get_ip(request)
print(user.ipaddress)
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('ve:dashboard')
else:
form = RegistrationForm()
return render(request, 'index.html', {'form': form})
forms.py
class RegistrationForm(UserCreationForm):
# birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
birth_date = forms.DateField(widget=SelectDateWidget(years=range(1999, 1910, -1)))
#ipaddress = forms.IntegerField(widget=forms.HiddenInput(), required=False)
class Meta:
model = User
fields = ('username', 'email', 'birth_date', 'password1', 'password2',)
exclude = ['ipaddress',]
index.html
<form method="post">
{% csrf_token %}
{% for field in form %}
<p class="text-left">
{{ field.label_tag }}<br>
{{ field }}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit">Sign up</button>
</form>
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
...
ipaddress = models.CharField(default="0.0.0.0", max_length=30)
This form was working fine before I tried adding the ipaddress field. I've been trying several versions and sometimes the form creates a new user but the ipaddress is not saved..
The current code above gives me there error on POST:
DoesNotExist at / User matching query does not exist. Due to this line "user.refresh_from_db() # Load the profile instance created by the Signal"

From the docs:
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.
So since you're passing commit in as False you're getting an unsaved instance back. Attempting to call refresh_from_db on an object that doesn't actually exist in the database will fail, as it is clearly doing. If the instance to a model has no id then refresh_from_db will fail when called on it.
As for the continuing inability to save IP address, I noticed that your form meta has the model set to the User object. The default Django User object has no ip address. I see that in the model file you linked you have a Profile model that does have an IP Address so in that case I think you simply have your form set up wrong. Or you need to handle the request differently.
Form change
Currently your form is attempting to create/modify a Django User model. Unless you've made a custom User model that you didn't show, this user model will not have an ipaddress as a field in the database meaning even if you set user.ipaddress = <address> and then save the user, the ip address won't persist outside of the current scope since all you did was declare a new variable for the user instance.
If you change your form to point at your Profile model you'll be able to save the address using profile.ipaddress = <address> and save it successfully. But you will have to update your template since by default it will only show the fields for your profile and not the user object associated with it.
Change Template/View
You can also change the template and view to accommodate it. Apparently your view is able to produce an IP Address using the get_ip function so for the time being I'll assume your template is fine as is so the only changes that need to be made are to your view.
Currently your view is getting an unsaved User instance back when it calls form.save. This means you need to save the user and then create a Profile model that references it with your ip address attached.
def index(request):
#request.session.flush()
if request.user.is_authenticated:
return redirect('ve:dashboard')
elif request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
# do anything you need to the unsaved user here
user.save()
prof = Profile.objects.create(user=user,
ipaddress=get_ip(request),
date=form.cleaned_data.get('birth_date')
# no need to save prof since we called objects.create
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('ve:dashboard')
else:
form = RegistrationForm()
return render(request, 'index.html', {'form': form})

Related

Django Form Reject Input if Specific User uses the same name twice and notifies user

In Django, I have a custom form that creates an "email group" within a modal. The email group model contains a number of attributes, including a unique ID for the email group, for the user, etc.
The idea is that a specific user shouldn't be able to enter the same name twice - and if they do, they should be notified.
It seems right now like the form is rejecting inputs that duplicate email_name (it doesn't get added to the database), but the message it's returning is New Email Added.
I've also been trying to get the email to show within the modal but that's a whole other issue.
form.py
class EmailCreateForm(ModelForm):
class Meta:
model = UserEmail
fields = ['email_name']
constraints = [
models.UniqueConstraint(fields=['user_id', 'email_name'], name='unique_name')
]
def __init__(self, *args, **kwargs):
super(EmailCreateForm, self).__init__(*args, **kwargs) # Call to ModelForm constructor
self.fields['email_name'].widget.attrs['rows'] = 1
views.py
def email(request):
if request.method == 'POST':
form = EmailCreateForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
messages.success(request, f'New Email Added')
return redirect('project-emails')
else:
messages.error(request, f'Email not Added')
return redirect('project-emails')
else:
form = EmailCreateForm()
return render(request, 'project/emails.html', {'form': form})
part of template emails.html
{% if messages %}
{% for message in messages %}
<div class="alert id = 'email-message'">
{{ message|escape }}
</div>
{% endfor %}
{% endif %}
According to Django documentation:
The classes defined in this module create database constraints. They are added in the model Meta.constraints option.
So, this should be added to the model class, not form.
Thus, your form.is_valid() will return true and the success message will be displayed. If you set unique constraints on the model class they should be checked in ModelForm instances in both steps: when validating the form and when saving to DB.

Django Validation is working on django admin but not working on html template

I'm creating a form where if we register it should save data to the database if the form is valid. otherwise, it should raise an error but it doesn't save data to the database, and also some fields are required but if I submit the form it doesn't even raise the error field is required. but if I register it manually on Django admin pannel it works perfectly fine.
here is my model:
class foodlancer(models.Model):
Your_Name = models.CharField(max_length=50)
Kitchen_Name = models.CharField(max_length=50)
Email_Address = models.EmailField(max_length=50)
Street_Address = models.CharField(max_length=50)
City = models.CharField(max_length=5)
phone = PhoneNumberField(null=False, blank=False, unique=True)
def __str__(self):
return f'{self.Your_Name}'
also, I disabled html5 validation
forms.py
class FoodlancerRegistration(forms.ModelForm):
phone = forms.CharField(widget=PhoneNumberPrefixWidget(initial="US"))
class Meta:
model = foodlancer
fields = "__all__"
views.py:
def apply_foodlancer(request):
form = FoodlancerRegistration()
return render(request, 'appy_foodlancer.html', {"form": form})
and finally Django template
<form method="POST" novalidate>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="cta-btn cta-btn-primary">Submit</button>
</form>
Thank you for your time/help
You don't have any form saving logic in your view.
Try something like this:
def apply_foodlancer(request):
if request.method == 'POST':
form = FoodlancerRegistration(data=request.POST)
if form.is_valid(): # if it's not valid, error messages are shown in the form
form.save()
# redirect to some successpage or so
return HttpResponse("<h1>Success!</h1>")
else:
# make sure to present a new form when called with GET
form = FoodlancerRegistration()
return render(request, 'appy_foodlancer.html', {"form": form})
Also check that the method of your form in your HTML file is post. I'm not sure if POST also works.
Avoid defining fields in a modelform with __all__. It's less secure, as written in the docs

Form is not saving user data into database Django

Python noob here trying to learn something very simple.
I'm trying to create a basic form that takes some personal information from a user and saves it into a sqlite3 table with the username of the user as the primary key.
My models.py looks like this:
class userinfo(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key= True,
on_delete=models.CASCADE)
name = models.CharField(max_length = 200, blank = True)
email = models.EmailField(max_length= 300, default = 'Null')
phone = models.CharField(max_length= 10, default = 'Null')
def __unicode__(self):
return self.user
forms.py:
class NewList(forms.ModelForm):
class Meta:
model = userinfo
exclude = {'user'}
views.py
def newlist(request):
if request.method == 'POST':
form = NewList(request.POST)
if form.is_valid():
Event = form.save(commit = False)
Event.save()
return redirect('/home')
else:
form = NewList()
return render(request, 'home/newlist.html', {'form': form})
html:
{% load static %}
<form action="/home/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
urls.py too, but I don't know how that would help:
urlpatterns = [
url(r'^newlist/$', views.newlist, name='newlist')
]
So when I go to the url, I see the form. I can then fill the form, but when I submit the form, the data doesn't go into the database.
What am I doing wrong here?
Thanks in advance!
I think all you need to do is just save the form if it's valid, probably also add the userinfo as an instance of the form. You are also exluding the user from the form and need to assign it manually.
def newlist(request):
if request.user.is_authenticated():
user = request.user
if request.method == 'POST':
form = NewList(request.POST, instance=user.userinfo)
if form.is_valid():
form.save(commit=false)
form.user = user
form.save()
return redirect('/home')
else:
form = NewList(instance=user.userinfo) # add this if you want it to automatically fill the form with the old data if there is any.
return render(request, 'home/newlist.html', {'form': form})
The rest look like it should work.Except you need to send the post URL back to newlist:
{% load static %}
<form action="/newlist/" method="POST">
{% csrf_token %}
{{ form.as_p }}
</form>
If users are assigned at the creation of the model the first time, you don't need the user save, but since this is saving a users data you want to make sure they are logged in anyway:
def newlist(request):
if request.user.is_authenticated():
user = request.user
if request.method == 'POST':
form = NewList(request.POST, instance=user.userinfo)
if form.is_valid():
form.save()
return redirect('/home')
else:
form = NewList(instance=user.userinfo) # add this if you want it to automatically fill the form with the old data if there is any.
return render(request, 'home/newlist.html', {'form': form})
The instance is the model it is either going to save to, or copying data from. In the: form = NewList(request.POST, instance=user.userinfo) part, it is taking the POST data from the form, and linking that to the specific model entry of user.userinfo, however, it will only save to the database when you call form.save().
The user.userinfo is just so you can get the correct form to save to, as userinfo is a onetoone model to user. Thus making it possible to get it with user.userinfo.
The form = NewList(instance=user.userinfo) part is where it takes the currently logged in user's userinfo and copies into the form before it is rendered, so the old userinfo data will be prefilled into the form in the html. That being if it got the correct userinfo model.

save() form from django don't save in DB

I want to save a username in database, but it doesn't work. Below is the code. I've created a DB named User and I'm trying to save the user who has been taking by the input from the html I've created. And my database User contains only username field. I used the UserCrationForm as default, and my database appear as polls_user in phpmyadmin. I don't think that's the problem. When I'm trying to save from shell, its working, using the save modelform.
views.py
def register_user(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
q = form.save(commit=False)
q.username = request.username
q.save()
return HttpResponseRedirect('/polls/login')
else:
messages.error(request, "Error")
args = {}
args.update(csrf(request))
args['form'] = UserCreationForm()
return render_to_response('polls/register.html', args, context_instance= RequestContext(request))
register.html
{% block content %}
<h2> Register</h2>
<form action="/polls/login/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Register">
</form>
{% endblock %}
I cant see where the problem is.
Someone help?
Problem is here: q.username = request.username .It should be:
def register_user(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
q = User() #import your own User model here.
q.username = request.user.username
q.save()
return HttpResponseRedirect('/polls/login')
PS: This will only get you the username of the logged in user.
EDIT:
(from comments)
As you can see, UserCreationForm is a modelform, where in meta class, model is auth.User model(check here). So your data is being saved in auth.User. So override the UserCreationForm like this (If you want to use the UserCreationForm):
#form
class MyUserCreationForm(UserCreationForm):
class Meta:
model = PollUser #Your poll user model
fields = ("username",)
#view
if request.method == 'POST':
form = MyUserCreationForm(request.POST)
if form.is_valid():
....
For this solution, you have to keep in mind that, you need to subclass PollUser model from auth.User model. If you want to use your own PollUser model (not subclassing from auth.User model), then I will suggest you to make a new modelform for PollUser and not use UserCreationForm.

Saving additional data to a user profile in Django

I've already enabled the ability for users to create profiles; however, I need to be able to save additional data to the profile once the user has already logged in.
Say that John is logged in. After he logs in, he decides that he wants to bookmark a certain term. Every time that he bookmarks a term (the url of the current page), it will be added to the "terms" section associated with his profile.
I'm not sure how to allow for the addition of more than one term - don't think CharField is correct, and I also don't know how to link the form in the template to the view so that it actually saves this data to the profile. Here is what I currently have:
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
terms = models.CharField(max_length=1000)
views.py
This is how I created my user:
def register(request):
context = RequestContext(request)
registered = False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
registered = True
else:
print user_form.errors, profile_form.errors
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render_to_response(
'app/register.html',
{'user_form': user_form, 'profile_form': profile_form, 'registered': registered},
context)
And this is what I'm attempting to do with terms:
def terms(request):
context = RequestContext(request)
url = request.get_full_path()
profile = UserProfile()
profile.topics = url
profile.save()
return render_to_response('app/page1.html', {}, context)
urls.py
url(r'^terms/$', views.terms, name='terms'),
And the template file.
<form method="post" action="{% url 'terms' %}" enctype="multipart/form-data">
{% csrf_token %}
<input type="submit" name="submit" value="Save" />
</form>
I'm think you can use https://github.com/brosner/django-bookmarks to save bookmarks for any user without your code.
Or add model smt about Term like this
class Term(models.Model):
user = models.ManyToManyField(User, related_name='terms')
term = models.CharField(max_length=1000)
and use user.terms.all() for get all user's terms.
But, if you need save your schema and models, you need custom field which will works like array field in postgres. If you use postgresql db, add https://github.com/ecometrica/django-dbarray to you project and use terms like TextArrayField, if you db is not postgres see here -
What is the most efficent way to store a list in the Django models?
second answer titled "Premature optimization is the root of all evil." by user jb.
Solution with relations is "normalized" - simple and strong
Solution with "array-field" is "demormalized" - faster but with risks of non-consistently data.

Categories