After the user registers, I am using signals to create a user profile, so they can fill in additional details (like country or website) that the standard registration form can't offer. The problem is the form is not displaying the contents. However I can fill in the same form on admin site easily, but I want to allow users to do it by themselves.
On Chrome I tried to inspect the problem, and where there is a form it says input='hidden'. What might be the problem?
Thank you in advance.
my views:
def edit_profile(request):
if request.method == 'POST':
edit_form = EditProfileForm(request.POST,
instance=request.user.profile)
if edit_form.is_valid():
edit_form.save()
messages.success(request, 'Your account has been updated!')
return redirect(profile)
else:
edit_form = EditProfileForm(instance=request.user.profile)
context = {'edit_form': edit_form}
return render(request, 'profile.html', context)
my profile.html:
<form method='POST'>
{% csrf_token %}
{{ edit_form }}
<button type="submit">Update</button>
</form>
models:
class Profile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=100, default='')
country = models.CharField(max_length=100, default='')
website = models.URLField(default='')
image = models.ImageField(default='images/profile.jpg',
upload_to='images')
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
if kwargs['created']:
profile = Profile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
forms.py:
class EditProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('status', 'website', 'description', 'country', 'user', )
Do you get an indentation error when you run your code?
If not can you please update your question with the correct indentation so that the SO people can help you troubleshoot.
Next up, do you have any group permissions in place for standard users vs non-standard user(admin)? I would check to see if they have the capability to modify their User objects freely.
Errors for the form are usually displayed by <ul class="errorlist"> FormsAPI, I would check for those. If none, then I would double check that the form being returned isn't actually blank by debugging it and looking at the __dict__ definition of that object. I can't give you any more suggestions until the indentation part is fixed so I can rule out any logic errors.
Found the problem: edit_form = EditProfileForm(instance=request.user.profile)
What you want to do is query the Profile object that belongs to the user, bold then pass it in as an instance to your EditProfileForm.
class EditProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('status', 'website', 'description', 'country', 'user', )
Your form's Meta is the Profile object not the User object.
Hope that helps, good luck!
Related
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 !!!
Good day Stackoverflow,
a user should be able to add multiple titles instead of always overwriting the one added title.
\\ views.py
def edit_profile(request):
try:
profile = request.user.userprofile
except UserProfile.DoesNotExist:
profile = UserProfile(user=request.user)
if request.method == 'POST':
form = UserProfileForm(request.POST, instance=profile)
if form.is_valid():
form.save()
return redirect('/test')
else:
form = UserProfileForm(instance=profile)
return render(request, 'forms.html', {'form': form, 'profile': profile})
\\models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
title = models.CharField(max_length=1024)
def __str__(self):
return str(self.title)
\\forms.py
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('title',)
Then the user has a form on the website where he can add the specific title.
Until now, however, every time the user fills out the title form, the value in the database is overwritten.
As it should be:
When a new title is added in the form, it should simply be added to it.
At the end I should have the possibility, with a Foor loop in the HTML template, to display all the added titles of the respective user.
Do you know how to do this?
If you are using a relational database, this functionality isn't really supported for a single field. Though, if you really wanted to, you could use a JSON field to make this work.
However, it is probably a better idea to use a separate table for titles.
To do this, you need to create a new Title object like:
class Title(models.Model):
Then, create a many-to-one relationship using ForeignKey:
class Title(models.Model):
text = models.CharField(max_length=1024)
user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
The on_delete method is required. This particular one will delete all Titles associated with a UserProfile if a UserProfile is deleted.
Now, if you want to associate a title object with a UserProfile, you would do it like this:
profile = UserProfile(user=request.user)
title = Title.objects.create(text='My Very First Title', user_profile=profile)
For more info on many-to-one relationships in Django: https://docs.djangoproject.com/en/4.0/topics/db/examples/many_to_one/
You can create new model and assign new with the ForeignKey field.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return ', '.join([title for title in self.titles.all()])
class UserTitle(models.Model):
title = models.CharField(max_length=1024)
userprofile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='titles')
def __str__(self):
return self.title
views.py:
def edit_profile(request):
...
if request.method == 'POST':
...
if form.is_valid():
form.instance.userprofile = request.user.userprofile
form.save()
return redirect('/test')
...
admin.py:
from django.contrib import admin
from your_app.models import UserProfile
class UserProfileAdmin(admin.ModelAdmin):
list_display = ['id', 'user', '__str__']
admin.site.register(UserProfile, UserProfileAdmin)
settings.py:
INSTALLED_APPS = [
...
'your_app',
...
In template, to make for loop just use:
{% for title in user.userprofile.titles.all %}
{{ title }}
{% endfor %}
or if you need only User titles in single string:
{{ user.userprofile }}
I am attempting to reuse my create form (EntryForm) for editing a model in Django. My Entry model has a unique slug that is generated on save. This works fine when creating an Entry, but shows the following error when I attempt to edit it:
Entry with this Slug already exists.
I saw several similar questions, but most were failing to set instance= when instantiating the form. I'm pretty sure I'm doing that part correctly.
I've removed other model fields from the code below for clarity.
Here is my model:
class Entry(models.Model):
title = models.CharField(max_length=128, blank=True)
slug = models.SlugField(unique=True, blank=True)
def save(self, *args, **kwargs):
if not self.title:
self.title = self.date.strftime('%B %-d, %Y')
self.slug = slugify(self.title)
super(Entry, self).save(*args, **kwargs)
My view:
def edit_entry(request, entry_slug):
entry = get_object_or_404(Entry, slug=entry_slug)
form = EntryForm(instance=entry, label_suffix='')
if request.method == 'POST':
form = EntryForm(request.POST, instance=entry, label_suffix='')
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print(form.errors)
return render(request, 'journal/entry/form.html', {'form': form})
My form:
class EntryForm(forms.ModelForm):
title = forms.CharField(required=False, max_length=128, label="Title (defaults to date)")
slug = forms.CharField(widget=forms.HiddenInput(), required=False)
class Meta:
model = Entry
exclude = ()
Any ideas?
I did finally figure this out.
The issue was stemming from the fact that I was reusing my create template for the edit form, but forgot to set the form action dynamically depending on which action I desired. So, my 'edit' form was rendering correctly, but actually submitting via the 'create' action.
Thanks to those who commented and to what ultimately led me to debugging the problem, this handy code snippet equivalent to Ruby's binding.pry:
import code; code.interact(local=dict(globals(), **locals()))
I did also take #xyres's advice and remove the slug from my form, as it was unnecessary.
New form:
class EntryForm(forms.ModelForm):
title = forms.CharField(required=False, max_length=128, label="Title (defaults to date)")
class Meta:
model = Entry
exclude = ['slug']
New final line of edit_entry():
return render(request, 'journal/entry/form.html', {'form': form, 'entry': entry})
Form action:
{% if entry %}
<form id="entry_form" method="post" action="/journal/entry/{{ entry.slug }}/edit">
{% else %}
<form id="entry_form" method="post" action="/journal/new_entry/">
{% endif %}
I am making django project and have one problem with uploading images in forms.
So, I tried to add one object with image, in admin this is working, but in form on site - not.
My views:
def newbook(request, user_id):
form = BookAdd(request.POST or None)
if form.is_valid():
book = form.save(commit=False)
book.author = get_object_or_404(User, pk=user_id)
book.save()
return redirect('../%s' % book.id)
return render(request, 'userbook/newbook.html', {'form': form})
My model:
class Book(models.Model):
"""Book is a compilation of sections with subjects."""
author = models.ForeignKey(AUTH_USER_MODEL)
name = models.CharField(max_length=100)
description = models.CharField(blank=True, max_length=256)
cover = models.ImageField(upload_to='img/bookcovers')
def __str__(self):
return self.name
My form:
class BookAdd(ModelForm):
class Meta:
model = Book
fields = ('name', 'description', 'cover')
When I add new book, I get an error "the field is required", maybe for field of cover, but image added. This work honestly on local server, but don't work on pythonanywhere.com
You have to change code
form = BookAdd(request.POST or None)
to
form = BookAdd(request.POST,request.FILES)
and your form should have enctype="multipart/form-data"
<form action="." method="post" enctype="multipart/form-data">
I'm trying to build a form to save Names and Email Adresses to my database. However, it doesn't save...
I've used an Inclusion Tag because I want to use the same form in different templates.
This is my models.py:
class Contact(models.Model):
FRAU = 'FR'
HERR= 'HR'
GENDER_CHOICES = (
(FRAU, 'Frau'),
(HERR, 'Herr'),
)
gender = models.CharField(max_length=2, choices=GENDER_CHOICES, default=FRAU)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=200)
email = models.EmailField()
def __unicode__(self):
return "%s %s" %(self.first_name, self.last_name)
This is my forms.py:
class FragenContactForm(ModelForm):
class Meta:
model = Contact
fields = ['gender', 'first_name', 'last_name', 'email']
This is my custom tags module:
from django import template
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from fragen.forms import FragenContactForm
register = template.Library()
#register.inclusion_tag('fragen/askforoffer.html', takes_context=True)
def askforoffer(context):
form = FragenContactForm(context['request'].POST or None)
if context['request'].method=='POST':
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('fragen/thanks.html'))
else:
messages.error(context['request'], "Error")
return {'form': FragenContactForm()}
After I fill in and submit the form, I see nothing in my database. Am I missing something?
Thanks!
I've used an Inclusion Tag because I want to use the same form in
different templates.
You can simply reuse the form - or as your form in this case is very simple, you can use the CreateView generic class based view and reduce your code even further.
Your view would contain just the following:
class OfferForm(CreateView):
template_name = 'fragen/askforoffer.html'
model = Contact
fields = ['gender', 'first_name', 'last_name', 'email']
success_url = 'fragen/thanks.html'
Django will automatically create the ModelForm, and handle the error redirection and saving of the fields for you.
In your fragen/askforoffer.html template, you need just this:
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Create" />
</form>
Finally, in your urls.py:
url(r'^submit-offer/$', OfferForm.as_view(), name='offer-form')
To display the same form in multiple places, just map it to a URL:
url(r'^another-form/$', OfferForm.as_view(), name='another-form')
Finally, __unicode__ method should return a unicode object; so in your model:
def __unicode__(self):
return u"{} {}".format(self.first_name, self.last_name)
The way you are trying to do it will not work because the template tag code will be executed before the template is rendered; so by the time the user sees the form, your tag code is already finished. There is no way to "trigger" it again; which is why you need a traditional view method which will accept the data entered into the form.
Post is a method of server request which is handled by views.
Inclusion tag is rendered along with the page (that is during server response). Thus page context can not get request.POST - of cause, if you don't send POST deliberately as a context variable to the page (but it won't be request.POST - just some_variable). It looks a bit weird..
You have to handle form-processing in a view function.
from django.shortcuts import redirect, render
from fragen.forms import FragenContactForm
def askforoffer(request):
form = FragenContactForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('specify_thank_url_here')
return render(request, 'fragen/askforoffer.html',
{ 'form': form })
I've never seen any form processing in an inclusion tag and I doubt this will work. Above view-function may point you in the right direction.