Django Form: Default Value in one of the fields - python

This is my form:
class FriendRequestForm(forms.ModelForm):
class Meta:
model = Friend
my model:
class Friend(models.Model):
user1 = models.ForeignKey(User, related_name='frienduser1')
user2 = models.ForeignKey(User, related_name='frienduser2')
date = models.DateTimeField(auto_now=True)
accepted = models.BooleanField(default=False)
class Meta:
unique_together = ('user1', 'user2',)
In the template, how can I set user2 to be the ID based on who's profile page I am on? So if I am user1, and I am on user2's page (where this form loads in the html), I want user2 in the form to be set properly from the html template. Thanks!

You can't set anything in templates but assume that you actually meant corresponding view. If so, you can set initial value for the form easily:
def profile_view(request, user_id):
user = User.objects.get(id=user_id)
form = FriendRequestForm(initial={'user2': user})

I do not know which User model class you are using, but I'm assuming it is django's default User class. In that case, you can get the currently logged in user using request.user, and use that to populate the template field.
# views.py
def foo(request):
user = User.objects.get(id=request.user.id)
# TODO: check this is a valid user
render(
request,
'template.html',
{
# pass this user's id as a template variable
# or pass the entire user object itself
'user1_id': user.id,
})
# template.html
<div id='user1_field'>{{ user1_id }}</div>
IMHO, explicitly passing in required data is better than passing the entire request object in to the template like this:
from django.template import RequestContext
def foo(request):
return render_to_response(
'index.html', {'form': form, },
context_instance = RequestContext(request))

Related

How to set a permanent value to a Django Form Field

I am building blogsite where authenticated user can add post. The form has three fields including 'user' field (which shows all the user list with a drop down option). The problem is authenticated user can also see other user name.
I have tried two solution
Exclude this field when rendering in template or
whatever the username is chosen the post post will be saved by the name of authenticated user
but the solution I want
'user' field will only show the name of the authenticated user and that will be submitted with title and description
class BlogForm(forms.ModelForm):
class Meta:
model = Blog
fields = '__all__'
view function
if fm.is_valid():
us = fm.cleaned_data['user']
ti = fm.cleaned_data['title']
ds = fm.cleaned_data['desc']
post = Blog(user=us, title=ti, desc=ds)
messages.success(request, 'Blog Created')
post.save()
{% csrf_token %}
{{form.user.label}}{{form.user}}<br><br>
{{form.title.label}}{{form.title}}
{{form.desc.label}} {{form.desc}}
in model form only include "title" and "desc" field so template not render "user" field, we can set user in views.py via dynamically
class BlogForm(forms.ModelForm):
class Meta:
model = Blog
fields = ('title','desc',)
#views.py here we can set user via dynamically user=request.user
if fm.is_valid():
ti = fm.cleaned_data['title']
ds = fm.cleaned_data['desc']
post = Blog(user=request.user, title=ti, desc=ds)
messages.success(request, 'Blog Created')
post.save()
In your Form class
def __init__(self, *args, **kwargs):
super(YourForm, self).__init__(*args, **kwargs)
self.fields['user'].disabled = True
initialise your form:
data = {'user': request.user}
fm = YourForm(initial=data)
next:
if fm.is_valid():
us = fm.cleaned_data['user']
ti = fm.cleaned_data['title']
ds = fm.cleaned_data['desc']
post = Blog(user=us, title=ti, desc=ds)
messages.success(request, 'Blog Created')
post.save()
Your form will get the user from request, so you do not have any dependency for user from form.

How do I add username of logged in user to model field in django

How to add username of currently logged in user to field in my model? For example, I need to store info about user like name, email and so on in model, other than default Django user model, but I still use default one to store credentials. I want to establish relationship between those, so I created username field in my model. How do I fill it with current user's username upon saving the corresponding form?
My model
class ApplicantProfile(models.Model):
name = models.CharField(max_length = 50)
dob = models.DateField()
email = models.EmailField()
description = models.TextField()
username = <something>
What do I change <something> with?
My form
class ApplicantProfileEdit(forms.ModelForm):
class Meta:
model = ApplicantProfile
fields = [
'name',
'dob',
'email',
'description',
]
My view
def ApplEditView(request):
form = ApplicantProfileEdit(request.POST or None)
if form.is_valid():
form.save()
form = ApplicantProfileEdit()
context = {
'form':form
}
return render(request, "applProfileEdit.html", context)
P.S. I tried to import models straight to my views.py, and assign request.user.username to username field of the model in my view, but it didn't work, just left that field empty. I had username as CharField when I tried this.
It is not a good idea to save the username itself, or at least not without a FOREIGN KEY constraint. If later a user changes their name, then the username now points to a non-existing user, if later another user for example changes their username to thatusername, then your ApplicantProfile will point to the wrong user.
Normally one uses a ForeignKey field [Django-doc], or in case each ApplicantProfile points to a different user, a OneToOneField [Django-doc]:
from django.conf import settings
from django.db import models
class ApplicantProfile(models.Model):
name = models.CharField(max_length = 50)
dob = models.DateField()
email = models.EmailField()
description = models.TextField()
# maybe a OneToOneField
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
In the view:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def appl_edit_view(request):
if request.method == 'POST':
form = ApplicantProfileEdit(request.POST)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('some-view-name')
else:
form = ApplicantProfileEdit()
context = {
'form':form
}
return render(request, 'applProfileEdit.html', context)
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

A form that changes email and password

I want to write a form that will display the user's email but allow them to change their password by entering their current password and their new password twice. I want to use a ModelForm, too.
I have the User:
# models.py
class User(AbstractBaseUser):
email = models.EmailField(unique=True)
And I've started on a form:
# forms.py
class ChangeAccountDetailsForm(forms.ModelForm):
class Meta:
model = User
fields = ('email',)
current_password = forms.CharField(widget=forms.PasswordInput)
password = forms.CharField(widget=forms.PasswordInput)
confirm_password = forms.CharField(widget=forms.PasswordInput)
I've created a simple view that only works with a GET request at the minute:
# views.py
def edit_account_details(request):
if request.method == 'GET':
account_form = ChangeAccountDetailsForm()
return render(request, 'freelancestudent/edit_account_details.html', {
{'form': account_form}
})
else:
pass
And a simple HTML file that simply calls {{form.as_p}}. When I run it as is I get the error unhashable type: 'dict' at {'form': account_form}. How can I display, then, the current user's email and allow functionality for changing password. Is this possible with a ModelForm or will I have to roll my own form and do all the logic myself?
Here :
return render(
request,
'freelancestudent/edit_account_details.html', {
{'form': account_form}
})
You have two sets of {}. The inner one defines a dict, the outer one defines a set, so it's equivalent to:
context = {'form': account_form}
whatever = set(context)
Now sets needs their values to be hashable (just like dict keys), and a dict is not hashable, hence your error message.
But anyway: render expects a dict, not a set, so what you want is:
return render(
request,
'freelancestudent/edit_account_details.html',
{'form': account_form}
)

Django Inclusion Tag doesn't post to database

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.

Tango With Django: User Authentication - User being saved but not receiving confirmation

I am on chapter 9 of Tango With Django:
http://www.tangowithdjango.com/book17/chapters/login.html#demo
Whenever I create a user, I get an error page on my browser as shown below:
IntegrityError at /rango/register/
rango_userprofile.user_id may not be NULL
Request Method: POST
Request URL: http://127.0.0.1:8000/rango/register/
Django Version: 1.7.1
Exception Type: IntegrityError
Exception Value:
rango_userprofile.user_id may not be NULL
Exception Location: C:\Python27\lib\site-packages\django\db\backends\sqlite3\base.py in execute, line 485
Python Executable: C:\Python27\python.exe
Python Version: 2.7.8
Python Path:
['C:\\Users\\Paul.Zovighian\\desktop\\tango\\tango_with_django_project',
'C:\\Python27\\lib\\site-packages\\pandas-0.14.1-py2.7-win32.egg',
'C:\\Python27\\lib\\site-packages\\pytz-2014.7-py2.7.egg',
'C:\\Windows\\system32\\python27.zip',
'C:\\Python27\\DLLs',
'C:\\Python27\\lib',
'C:\\Python27\\lib\\plat-win',
'C:\\Python27\\lib\\lib-tk',
'C:\\Python27',
'C:\\Python27\\lib\\site-packages',
'C:\\Python27\\lib\\site-packages\\win32',
'C:\\Python27\\lib\\site-packages\\win32\\lib',
'C:\\Python27\\lib\\site-packages\\Pythonwin']
Server time: Fri, 12 Dec 2014 16:50:14 +0000
I can see that there is an integrity error, but I am not sure why this is the message I get. If I try registering that user again, it won't let me because it says that that username already exists. So it's like, working for registering new users, but it just doesn't acknowledge the successful registration.
Here is my code:
models.py
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
def __unicode__(self):
return self.title
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
website = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_images', blank=True)
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
views.py
from django.http import HttpResponse
from django.shortcuts import render
from rango.models import Category
from rango.models import Page
from rango.forms import CategoryForm
from rango.forms import PageForm
from rango.forms import UserForm, UserProfileForm
def index(request):
# Query the database for a list of ALL categories currently stored.
# Order the categories by no. likes in descending order.
# Retrieve the top 5 only - or all if less than 5.
# Place the list in our context_dict and dictionary which will be passed to the template engine.
category_list = Category.objects.order_by('-likes')[:5]
page_list = Page.objects.order_by('-views')[:5]
context_dict = {'categories': category_list, 'pages': page_list}
# Render the response and send it back!
return render(request, 'rango/index.html', context_dict)
def about(request):
context_dict = {'italicmessage': "I am italicised font from the context"}
return render(request, 'rango/about.html', context_dict)
def category(request, category_name_slug):
# Create a context dictionary which we can pass to the template rendering engine
context_dict = {}
try:
# Can we find a category name slug with the given name?
# If we can't, the .get() method raises a DoesNotExist exception.
# So the .get() method returns one model instance or raises an exception.
category = Category.objects.get(slug=category_name_slug)
context_dict['category_name'] = category.name
# Retrieve all the associated pages.
# Note that filter returns >= 1 model instance.
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
# We also add the category object from the database to the context dictionary.
# We'll use this in the template to verify that the category exists.
context_dict['category'] = category
context_dict['category_name_slug'] = category_name_slug
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything - the template displayes the "no category message for us."
pass
# Go render the response and return it to the client.
return render(request, 'rango/category.html', context_dict)
def add_category(request):
# A HTTP POST?
if request.method == 'POST':
form = CategoryForm(request.POST)
# Have we been provided with a valid form?
if form.is_valid():
# save the new category to the database.
form.save(commit=True)
# Now call the index() view.
# The user will be shown the homepage.
return index(request)
else:
# The supplied form contained errors - just print them to the terminal.
print form.errors
else:
# If the request was not a POST, display the form to enter details.
form = CategoryForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'rango/add_category.html', {'form': form})
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
return category(request, category_name_slug)
else:
form = PageForm()
context_dict = {'form': form, 'category': cat, 'category_name_slug': category_name_slug}
return render(request, 'rango/add_page.html', context_dict)
def register(request):
# A boolean value for telling the template whether the registration was successful.
# Set to False initially. Code changes value to True when registration succeeds.
registered = False
# If it's a HTTP POST, we're interested in processing form data.
if request.method == 'POST':
# Attempt to grab information from the raw form information
# Note that we make use of both UserForm and UserProfileForm.
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
# If the two forms are valid...
if user_form.is_valid() and profile_form.is_valid():
# Save the user's form data to the database.
user = user_form.save()
# Now we hash the password with the set_password method.
# Once hashed, we can update the user object.
user.set_password(user.password)
user.save()
# Now we sort out the UserProfile instance.
# Since we need to set the user attribute ourselves, we set commit=False
# This delays saving the model until we're ready to avoid integrity problems.
profile = profile_form.save()
profile.user = user
# Did the user provide a profile picture?
# If so, we need to get it from the input form and put it in the UserProfile model.
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
# Now we save the UserProfile model instance.
profile.save()
# Update our variables to tell the template registration was successful.
registered = True
# Invalid form or forms - mistakes or something else?
# Print problems to the terminal.
# They'll also be shown to the user.
else:
print user_form.errors, profile_form.errors
# Not a HTTP POST, so we render our form using two ModuleForm instances.
# These forms will be blank, ready for user input.
else:
user_form = UserForm()
profile_form = UserProfileForm()
# Render the template depending on the context.
return render(request,'rango/register.html', {'user_form': user_form, 'profile_form': profile_form, 'registered': registered} )
forms.py
from django import forms
from django.contrib.auth.models import User
from rango.models import Page, Category, UserProfile
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128, help_text="Please enter the category name.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
slug = forms.CharField(widget=forms.HiddenInput(), required=False)
# An inline class to provide additional information on the form.
class Meta:
# Provide an association between the ModelForm and a model
model = Category
fields = ('name',)
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.URLField(max_length=200, help_text="Please enter the URL of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
model = Page
exclude = ('category',)
# or specify the fields to include (.i.e. not include the category field)
#fields = ('title', 'url', 'views')
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
# If url is not empty and doesn't start with 'http://', prepend 'http://'.
if url and not url.startswith('http://'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username','email','password')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('website', 'picture')
I think I have all relevant files included here, but let me know if I could provide any other info to clear things up!
Thanks in advance
Your comment says "Since we need to set the user attribute ourselves, we set commit=False", but you don't actually do that. It should be:
profile = profile_form.save(commit=False)
In future, please cut your code down to the minimum that exhibits your problem: the error was occurring on register, you didn't need to show all the code relating to categories.

Categories