autopopulate from user django - django

I'm trying to make a form for updating user accounts in Django that is autopopulated with the current account data for that particular user. I can do this with HTML, but would rather find a way to make it work using Django's form system. I can't use Django's built-in user management due to certain constraints and am having to construct my own. I'm lost on where to start with this.

If you're using a normal form (sublassing forms.Form), pass data in using the initial keyword argument to your form constructor:
# forms.py
class MyUserForm(forms.Form):
username = forms.CharField(...
first_name = forms.CharField(...
...
# views.py
if request.method == 'POST':
# Process form
form = MyUserForm(request.POST)
...
else:
form = MyUserForm(initial={
'username': request.user.username,
'first_name': request.user.first_name,
...
}
...
An even easier way, though, is using Django's ModelForms. Something like:
# forms.py
class MyUserForm(forms.ModelForm):
class Meta:
model = User
# views.py
if request.method == 'POST':
form = MyUserForm(request.POST, instance=request.user)
...
else:
form = MyUserForm(instance=request.user)
...

Read the forms chapter of The Django Book online, for free. Then look into initial_data passed to forms. That should get you rolling.

Related

How to link two forms (wagtail form and django form) with a foreign key?

I'm using a django form in conjunction with a wagtail form. The django form will record some fields that will be on any form of this type: name, email and the wagtail form will record extra data defined by the form page creator specific to that instance.
I've overloaded the serve method to capture both sets of data and I can process both forms, but I'm stuck when trying to add the logic to relate the form contents to each other so that when one submission set is deleted, the other set will be as well. I think what I need is a foreign key.
The following code fails at form_submission.event_submission = a.id where I'd like to take the id from the wagtail form submission and add that as a foreign key to the django form, so that when the wagtail form portion is deleted, the other is deleted as well, and so that I can have a usable link between the two form submissions.
def serve(self, request, *args, **kwargs):
if request.method == 'POST':
form = EventSignupForm(request.POST)
wagtail_form = self.get_form(request.POST, request.FILES, page=self, user=request.user)
if form.is_valid() and wagtail_form.is_valid():
a = self.process_form_submission(wagtail_form)
form_submission = form.save(commit=False)
form_submission.event_submission = a.id
form_submission.save()
return self.render_landing_page(request, form_submission, *args, **kwargs)
else:
form = EventSignupForm()
wagtail_form = self.get_form(page=self, user=request.user)
context = self.get_context(request)
context['form'] = form
context['wagtail_form'] = wagtail_form
return TemplateResponse(
request,
self.get_template(request),
context
)
The form submission class and django model form looks like this. I think the ForeignKey I have in the Model isn't right, but I don't know. Any help?
class EventFormSubmission(AbstractFormSubmission):
cancellation_id = models.CharField(max_length=7)
class EventSignup(models.Model):
"""
A model to contain signup info for an event: name, email.
"""
event_submission = models.ForeignKey(EventFormSubmission, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
email = models.EmailField()
I solved this by adding the extra fields I wanted (name, email) to the EventFormSubmission and then using a regular django form (not a ModelForm) to collect these pieces of information.

Different ways to save form values to the database

I have started learning Django recently using a Udemy course. While going through the course instructor asked to save values from a Form to database.
After searching on the internet I figured out how to put form values into database and everything is working fine. Below is my views.py and forms.py files.
forms.py
class FormName(forms.Form):
fname = forms.CharField( label="First Name")
lname = forms.CharField(label="Last name:")
email = forms.EmailField()
verify_email = forms.EmailField(label='Verify Email:')
def clean(self):
all_clean_data = super().clean()
email = all_clean_data['email']
vmail = all_clean_data['verify_email']
if email != vmail:
raise forms.ValidationError("Check the emails")
views.py
def signup(request):
form = forms.FormName()
if request.method == 'POST':
form = forms.FormName(request.POST)
if form.is_valid():
post = User()
post.fname=request.POST.get('fname')
post.lname=request.POST.get('lname')
post.email=request.POST.get('email')
post.save()
return render(request,'third_app/greet.html')
else:
return render(request,'third_app/oops.html',{'form':form})
return render(request, 'third_app/signup.html',{'form':form})
Now coming to question, the instructor is using Meta class to store the form values to the database. Below are his forms.py and views.py files. I am curious about what the difference is between my method and the instructor's.
forms.py
class FormName(forms.ModelForm):
class Meta():
model = User
fields = 'all'
views.py
def signup(request):
form = forms.FormName()
if request.method == 'POST':
form = forms.FormName(request.POST)
if form.is_valid():
form.save(commit=True)
return render(request,'third_app/greet.html')
else:
return render(request,'third_app/oops.html',{'form':form})
return render(request, 'third_app/signup.html',{'form':form})
Thanks.
The Django docs explain this very well. It's what is known as a ModelForm:
If you’re building a database-driven app, chances are you’ll have forms that map closely to Django models. For instance, you might have a BlogComment model, and you want to create a form that lets people submit comments. In this case, it would be redundant to define the field types in your form, because you’ve already defined the fields in your model.
For this reason, Django provides a helper class that lets you create a Form class from a Django model.
So, to answer your question, your method uses a regular form (forms.Form) where you define the form fields, perform validation and then save each field individually in your view. When using form.ModelForm, field validation and saving is taken care of for you. Seeing as you have already defined what your fields are, the ModelForm uses this to perform the validation. The save() method conveniently saves each field to the database.

Django Form getting invalid

I am newbie to Django. I have some troubles with forms after moving into new verison. Following,
1, The model
class UserProfileDetails(models.Model):
user = models.OneToOneField(User)
profilePicture = models.ImageField('Profile Picture',upload_to='static/ProfilePic/', null=True,blank=True)
def __str__(self):
return self.user.username
2, The form
class imageUploadForm(forms.ModelForm):
class Meta:
model= UserProfileDetails
fields = ['user','profilePicture']
3, And finally the view function
def upload_pic(request):
current_user = request.user
if request.method == 'POST':
form = imageUploadForm(request.POST, request.FILES)
if form.is_valid():
pic = form.cleaned_data['profilePicture']
m = UserProfileDetails(user= current_user.id,profilePicture=pic)
m.save()
else:
raise NotImplemented("What if the user doesn't have an associated profile?")
return HttpResponseRedirect(reverse('polls:profile'))
This code worked with Django 1.8. But after porting to Django 1.10.4, the form is getting invalid. I believe, the problem is with OneToOneField.
IMP: Also, i am using pinax account app for account management.
Why this form is getting invalid?
When you submit the form, it doesn't seem as though a correct input has been given for both fields (user and profile picture). My guess is that you aren't sending through the user in the form which means it is invalid. So you are only uploading the image.
You do not need to have 'user' in the form fields attribute as you already access that in the view with 'request.user'. So remove the 'user' field from the form.
Also, to make sure it is correct, change 'user=current_user.id' to 'user=current_user' so you are match instance with instance rather than instance with id.

Django Design Pattern - request.user in Model

I run into this pattern all the time and I'm wondering if there's a better way to handle it. Lots of my models contemplate the idea of 'creator' - in other words, I want to make sure the user who created the object is saved as the creator. As such, my models almost always include
creator = models.ForeignKey(User)
There doesn't seem to be a way of defaulting this user to the user who created it (request.user). As such I find myself building model forms and adding creator as a HiddenInput()
class MyModelForm(ModelForm):
class Meta:
model = MyModelForm
fields = ['name', 'creator']
widgets = {
'creator': HiddenInput()
}
and then binding the form in the view with initial
form = MyModelForm(initial={'creator': request.user})
and checking on POST to make sure no one dickered with the form (full view):
def create(request):
form = MyModelForm(initial={'creator': request.user})
if request.method == 'POST':
if int(request.POST['creator']) != int(request.user.id):
return render(request,'500.html', {'message':'form tampering detected'})
form = FeedGroupForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('index'))
return render(request, 'mymodelformpage.html',{'form':form})
I'm fine with this but it seems like an anti-pattern. It strikes me that there ought to be a way to default the creator in the model.
creator = models.ForeignKey(User, default=request.user)
Or do it in a post_save perhaps?
No, this is not the right way. The correct way is to exclude the creator field from the form, then set it on save:
if form.is_valid:
obj = form.save(commit=False)
obj.creator = request.user
obj.save()
... redirect ...

Possible to do with django forms?

I have a form where an administrators enters a list of comma-separated email addresses, and the form does validation on each email address before adding it to the db. I was able to do this just fine with using my own (non-django) form. I tried to migrate this over to using modelforms, but ran into a few problems. Here is the code I currently have --
# model
class EmailList(models.Model):
email = models.EmailField(blank=True)
network = models.ForeignKey(Network)
class EmailListForm(ModelForm):
class Meta:
model = EmailList
def clean_email(self):
if self.cleaned_data['email']:
valid_emails = []
for x in self.cleaned_data['email'].split(','):
x = x.strip().lower()
valid_emails.append(x)
return valid_emails
# in views
def email(request):
if request.POST.get('email'):
for email in form.cleaned_data.get('email'): ### ??
if form.is_valid(): ### ??
EmailList.objects.create(email = email, network=Network.objects.get(id=request.POST['network']))
return redirect('.')
I am having trouble because I can't call on the cleaned_data() until the form is validated, but the form will not validate as a whole (only its iterations will). Is it possible to construct this function using django's forms? If so, how would I accomplish this task? Thank you.
In this case I wouldn't use a ModelForm because they are for the case that you want to represent one Model instance by one Form. Here you want to produce multiple instances with one form. So just write a common form with a custom field (there is acutally an example just for this in the Django docs) and maybe a custom save method:
from django import forms
from django.core.validators import validate_email
class MultiEmailField(forms.Field):
def to_python(self, value):
"Normalize data to a list of strings."
# Return an empty list if no input was given.
if not value:
return []
return value.split(',')
def validate(self, value):
"Check if value consists only of valid emails."
# Use the parent's handling of required fields, etc.
super(MultiEmailField, self).validate(value)
for email in value:
validate_email(email)
class EmailListForm(forms.Form):
emails = forms.MulitEmailField()
network = forms.ModelChoiceField(queryset=Network.objects.all())
# save the emails to the db
def save(self):
for email in self.cleaned_data.get('emails'):
EmailList.objects.create(email = email,
network=self.network)
# in views
def email(request):
if request.method == 'POST':
form = EmailListForm(request.POST)
if form.is_valid():
form.save()
return redirect(...somewhere...)
else:
form = EmailListForm()
return render(request, 'some/template.html', { 'form': form }