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.
Related
I am starting with Django, and I have a question about the connection between a post and the user who created it. For now, I managed to create the link, however, whenever I create a new post, the user id is always the default one, thus one. I want to make it in a way that the user id is the id of the person creating the post, and for some reason, it never works. The other option I tried is to put "user" into the form but the problem is that then the user can choose which user he is, which is risky. So is there any way to make it automatic? That when the post is created, the right user id is directly connected to it? Thank you for any help!!
model.py
"""
class Post(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE, default=1)
image = models.ImageField(default="man.jpg")
titre = models.CharField(max_length=50)
slug = models.SlugField(max_length=100)
date_publication = models.DateTimeField(auto_now_add=True)
"""
view.py
"""
#login_required
def post_create(request):
if request.method == "POST":
post_form = PostForm(request.POST)
if post_form.is_valid():
post_form.save()
messages.success(request, 'Your post was successfully created!')
return redirect('seed:view_seed')
else:
messages.error(request, 'Please correct the error below.')
else:
post_form = PostForm(request.POST)
return render(request, "post/create.html", context={"post_form": post_form})
"""
forms.py
"""
class PostForm(ModelForm):
class Meta:
model = Post
fields = ["user", "image", "titre", "slug"]
"""
You remove the user field from the fields in the form:
class PostForm(ModelForm):
class Meta:
model = Post
# no user ↓
fields = ['image', 'titre', 'slug']
and in the view you add the logged in user to the instance wrapped in the form:
#login_required
def post_create(request):
if request.method == 'POST':
post_form = PostForm(request.POST)
if post_form.is_valid():
# add user to the instance ↓
post_form.instance.user = request.user
post_form.save()
messages.success(request, 'Your post was successfully created!')
return redirect('seed:view_seed')
else:
messages.error(request, 'Please correct the error below.')
else:
post_form = PostForm()
return render(request, "post/create.html", context={"post_form": post_form})
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.
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].
I've created a normal Django posts app, which basically let's users create posts and it's content.
Now the thing is that I implemented the create post form as a ModelForm in forms.py. Now if it wasn't a ModelForm and just a html-form, I would have used request.POST.get('data')
But now I use
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = (
'title',
'content',
'image',
)
Models.py
class Post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(null=True,blank=True)
content = models.TextField()
user = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
Views.py
def create(request):
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect('/home')
return render(request,'create.html',{'form':form})
How can I relate a user to a created post?
You can simply assign the user to the instance in between the two save functions:
instance = form.save(commit=False)
instance.user = request.user
instance.save()
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))
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.