Auto Inserting Logged In Users Username in Django - python

In the Django Administrative Interface I'd like to Automatically Insert a logged in users username along with a blog post when the publish it, currently I have it displaying every user in a drop down to select from but obviously this is not great so I'd like it to automatically input this.
Here is my code:
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
published_date = models.DateTimeField('date published')
author = models.ForeignKey(User, db_column="published_who")
def __unicode__(self):
return self.title
admin.py
from blog.models import Post
from django.contrib import admin
class PostAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.author = request.user
obj.save()
admin.site.register(Post, PostAdmin)
Many Thanks!

As I understand issue you need to exclude author from admin form:
class PostAdmin(admin.ModelAdmin):
exclude = ['author']

What you should use is in the Django docs: https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey
You can overwrite the default behaviour of a ForeignKeyField in the admin with this.
Something along the lines of:
def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
if db_field.name == "author":
kwargs["initial"] = request.user
return super(PostAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
*This is untested
EDIT:
I didn't know whether you wanted to entirely disable the dropdown. With this method you wont. Instead you will have a default value of request.user but still be able to select another user.
If you want to make it a drop down with only one selection (weird behaviour :P) you could add:
kwargs["queryset"] = Post.objects.filter(author=request.user)

Related

How to attach current logged in user to object when object is created from django admin

I'm working on website whose an app which has class called Members whose a field that is related to the builtin User class from django.contrib.auth.models and it looks like
class Members(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
member_image = models.ImageField(upload_to='unknown')
member_position = models.CharField(max_length=255)
...
So as you can see when I'm adding member_image as a user I have also to select the user which doesn't make sense to me because I want to detect which user is logged in and pass his/her id as default parameter
like
class Members(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, default=request.user.id)
and after remove the user field in the admin panel like
class MembersAdmin(admin.ModelAdmin):
fields = ('member_image', 'member_position', ...)
so that if the user field doesn't selected it will set the logged in user_id by default
but to access request out of the views.py is not possible.
so how will I achieve this I also tried the following answers
Access session / request information outside of views in Django
Accessing request.user outside views.py
Django: How can I get the logged user outside of view request?, etc
but still not get it
Modify MembersAdmin save_model method and attach request.user to the object prior to saving.
class MembersAdmin(admin.ModelAdmin):
fields = ('member_image', 'member_position', ...)
def save_model(self, request, obj, form, change):
obj.user = request.user
super().save_model(request, obj, form, change)
For exclude the current logged in User for particular page or view, You can try this :-
from django.contrib.auth import get_user_model
User = user_model()
def some_view(request):
exclude_current_user = User.objects.exclude(user=request.user)

Own data for everyuser in django

So I am building a to do app in Django. I have created databases for the users and todo items. But I have a problem, how can each user have its own data. Like every user should add their own data. It seems like there is no answer out there.
My models.py
class Task(models.Model):
title = models.CharField(max_length=200)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
My forms.py
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username','email','password1','password2']
So how can I connect those both. I have red that I have to use foreign key. But I really don't understand how I can do it
You specify a ForeignKey [Django-doc] in the Task model that refers to the user that constructed it:
# app/models.py
from django.db import models
from django.conf import settings
class Task(models.Model):
title = models.CharField(max_length=200)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
return self.title
You can then make a ModelForm where you exclude the user. For example:
# app/forms.py
from django import forms
from app.models import Task
class TaskForm(forms.ModelForm):
class Meta:
model = Task
exclude = ['user']
Then in the view we can "inject" the user in the instance we create, for example:
# app/views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
from app.forms import TaskForm
#login_required
def create_task(request):
if request.method == 'POST':
form = TaskForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('name-of-some-view')
else:
form = TaskForm()
return render(request, 'some_template.html', {'form': form})
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.

IntegrityError NOT NULL constraint failed

I'm building a simple blog app using Django. I want to realize the function of adding a new blog using form. Some problems occurs.
Here is my models.py
from django.db import models
from django.utils import timezone
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
class Blog(models.Model):
title=models.CharField(max_length=60)
content=models.TextField()
author=models.ForeignKey('auth.User',on_delete=models.CASCADE,)
date=models.DateTimeField(default=timezone.now)
slug=models.SlugField(null=True,unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Blog, self).save(*args, **kwargs)
def __str__(self):
return self.title
class UserProfile(models.Model):
user=models.OneToOneField(User)
website=models.URLField(blank=True)
def __str__(self):
return self.user.username
forms.py
from django.template.defaultfilters import slugify
from blog.models import UserProfile
from django.contrib.auth.models import User
class BlogForm(forms.ModelForm):
title=forms.CharField(max_length=60,
help_text="blog title")
content=forms.CharField(help_text="blog content")
author=forms.CharField(help_text="blog author")
date=forms.DateTimeField(help_text="blog date")
class Meta:
model=Blog
fields=('title',)
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',)
the add_blog method in views.py
def add_blog(request):
form=BlogForm()
if request.method =='POST':
form=BlogForm(request.POST)
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print(form.errors)
return render(request, 'add_blog.html',{'form':form})
When I want to add a new blog in my webpage, I can't input the record. It shows me
IntegrityError at /add_blog/
NOT NULL constraint failed: blog_blog.author_id
Could anybody help me fix this problem? Thanks a lot!
In your models, your Blog class requires:
Title
An author, of type auth.User
content
The first step, is to remove the author field from your form:
class BlogForm(forms.ModelForm):
title=forms.CharField(max_length=60,
help_text="blog title")
content=forms.CharField(help_text="blog content")
# author=forms.CharField(help_text="blog author")
date=forms.DateTimeField(help_text="blog date")
class Meta:
model=Blog
fields=('title','content','date')
Next, is to add the logged in user as the author in your view:
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
# makes sure this view is called with a valid user
# https://docs.djangoproject.com/en/2.0/topics/auth/default/#the-login-required-decorator
#login_required
def add_blog(request):
form = BlogForm(request.POST or {})
if form.is_valid():
temp = form.save(commit=False)
temp.author = request.user # add the logged in user, as the
# author
temp.save()
return redirect('/')
return render(request, 'add_blog.html',{'form':form})
Another way to view this problem... Perhaps you can Try clearing your migration files , and re-run makemigrations to see if it catches anything off about your models. It may ask you for a default value for some of the fields; and this should ring a bell to assign null=True where appropriate. Personally this is quite a common integrity conflict for me (i'm new to the framework) especially when i've done many unplanned on the fly mods to models on the same db.

How to get currently logged user id in form model in Django 1.7?

Let's say I have a webpage that displays songs. And let's say there are public and private songs. Public songs are available for everyone to see, while private songs are songs that a certain user has created and are only available for him to see. So the user should only see those songs with the owner_id == NULL and owner_id == currently_logged_in_user_id (his own id)
Model:
import ....
class Song(models.Model):
name = models.CharField(max_length=100)
duration = models.IntegerField(max_length=15)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
def __unicode__(self):
return self.name
View:
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from songapp.models import Song
from songapp.forms import SongInfoForm
#login_required
def song_info(request):
song = get_object_or_404(Box)
song_status = song.get_status()
form = SongInfoForm(initial={'song_list': song.song_list})
return render(request, 'songapp/song_info.html',
{'form': form, 'song': song, 'song_status': song_status})
Form:
from django import forms
from django.forms import ModelChoiceField
from songapp.models import Song
class SongInfoForm(forms.Form):
--> selected_songs = Song.objects.filter(owner=None) | Song.objects.filter(owner=3)
song_list = ModelChoiceField(queryset=selected_songs, required=False)
Note the line with the arrow in the Form file. This is where the problem lies. The code works now, but the
(owner = 3)
is hardcoded. I know for a fact that my users id is 3. But I want it to work properly. It should be something like this:
(owner = currently_logged_in_user.id)
I'm still very new to Django and Python and I don't know how to pass the users id to the SongInfoForm FormModel.
I've figured it out.
In views.py change:
form = SongInfoForm(initial={'song_list': song.song_list}, user=request.user)
And thanks to the answers before and this example
django form: Passing parameter from view.py to forms gives out error
I've came up with this, and it works like a charm.
In forms.py
class SongInfoForm(forms.Form):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(SongInfoForm, self).__init__(*args, **kwargs)
self.fields['song_list'] = forms.ModelChoiceField(queryset=Song.objects.filter(owner=None) | Song.playlist.objects.filter(owner=user), required=False)
OK, my bad. Didn't read enought to see problem lies in the form, But according to this post: https://stackoverflow.com/a/5122029/2695295 you could rewrite your for like this:
class SongInfoForm(forms.Form):
def __init__(self, user, *args, **kwargs):
self.user = user
super(SongInfoForm, self).__init__(*args, **kwargs)
selected_songs = Song.objects.filter(owner=None) | Song.objects.filter(owner=user.id)
song_list = ModelChoiceField(queryset=selected_songs, required=False)
and then in view create your form like this:
form = SongInfoForm(request.user, initial={'song_list': song.song_list})
this way form object should have access to user.

Author foreignkey field automatically chosen in admin space of blog app

I have created a blog app which its model has an author field like this:
author = models.ForeignKey(User)
I'm trying to modify default add view in django admin in order to get the added post take the logged first name user. How? This way:
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'author':
kwargs['initial'] = request.user.id
return db_field.formfield(**kwargs)
return super(PostAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Well, in add view the select input which corresponds to author field shows the username. I want this select shows first_name + last_name field and not username field. And finally, when i success in this task, i want to hide this select. The logged user must not change the user who sends an entry to the blog.
I have been several hours working on this with no success. Help please!
Thanks a lot mates.
One way to make the author foreign key field show User.first_name + User.last_name is to use a proxy model for the User in author:
# your_app.models
from django.contrib.auth.models import User
class AuthorUser(User):
class Meta:
proxy = True
def __unicode__(self):
return '%s %s' % (self.first_name, self.last_name)
class YourModel(models.Model):
author = models.ForeignKey(AuthorUser)
To make the field go away, you can simply mark it editable=False. Hope that helps you out.
Edit:
In Django 2.0, you will need an on_delete parameter in order to use ForeignKey.
class YourModel(models.Model):
author = models.ForeignKey(AuthorUser, on_delete=models.CASCADE)

Categories

Resources