Own data for everyuser in django - python

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.

Related

How do I make my Django dropdown form show items owned by a user and not all users?

I am having trouble displaying items owned only by specific users, rather than each user getting to see all items in my database. Below is an example of a non-superuser who has access to all items in my database when this user should only have access to the ones they created
image of dropdown menu with all items instead of just some
Below are the Form, View, and Models I have created in attempt to do this.
forms.py
class RoutineForm(forms.ModelForm):
"""creates a form for a routine"""
class Meta:
model = Routine
fields = ['workout']
labels = {'workout': 'Workout'}
Here is the views.py
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
#login_required
def routine(request):
"""display a dropdown of all workouts for a user"""
if request.method != 'POST':
form = RoutineForm()
else:
form = RoutineForm(data=request.POST)
if form.is_valid():
new_routine = form.save(commit=False)
new_routine.save()
return redirect('index')
context = {'workouts':workouts, 'form':form}
return render(request, 'routine_workouts_app/routine.html', context)
and finally, the models.py file
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Workout(models.Model):
"""A workout group the user will use to workout"""
text = models.CharField(max_length=200) #titles should not be too long
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
"""Return a string representation of the model"""
return self.text
class Routine(models.Model):
"""Shows a routine"""
workout = models.ForeignKey(Workout, on_delete=models.CASCADE)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return 'this is a routine'
Am I missing some sort of filter? Something Fundamental? I have been able to filter some other views that I have made. For example:
#login_required
def workouts(request):
"""This is the page that will display all the workout groups"""
workouts = Workout.objects.filter(owner=request.user).order_by('text') #filter by user ownership
context = {'workouts': workouts}
return render(request, 'routine_workouts_app/workouts.html', context)
on line 4 of this snippet, I have successfully filtered items that only belong to a specific user. But this is not a form, just a display on an html file. I have tried to put a similar line in the routine view function but it did not work. Any suggestions?
You can add a parameter to the constructor of the RoutineForm, that will filter the queryset specified to link to a Workout. This thus means that the form looks like:
class RoutineForm(forms.ModelForm):
"""creates a form for a routine"""
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
self.fields['workout'].queryset = Workout.objects.filter(owner=user)
class Meta:
model = Routine
fields = ['workout']
labels = {'workout': 'Workout'}
In the view, we then can construct a Form where we pass the logged in user to the constructor of the form:
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
#login_required
def routine(request):
"""display a dropdown of all workouts for a user"""
if request.method != 'POST':
form = RoutineForm(user=request.user)
else:
form = RoutineForm(data=request.POST, user=request.user)
if form.is_valid():
form.instance.owner = request.user
new_routine = form.save()
return redirect('index')
context = {'workouts':workouts, 'form':form}
return render(request, 'routine_workouts_app/routine.html', context)

How can I assign the logged in (authenticated) user to the form data they submit?

I am developing an employee feedback interface with Django. They shall be able to log in and submit a complaint. That complaint is supposed to be stored in the database with the user who submitted it as an attribute.
I have tried to somehow pass the user to the form so that the form saves the authenticated user's username, but I haven't been able to pass data from a view to a form.
I have been able to integrate a ModelChoiceField() to the ModelForm, but that lets the authenticated user manipulate the username that the complaint is going to be associated with.
models.py:
from django.db import models
from django.contrib.auth.models import User
class Complaint(models.Model):
complaint_text = models.CharField(max_length=1000, default='')
switch_schedule_yes_or_no = models.BooleanField(default=True)
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
views.py:
from .forms import ComplaintForm
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
#login_required()
def complaint_view(request):
form = ComplaintForm(request.POST)
if form.is_valid():
form.save()
form = ComplaintForm()
context = {
'form': form,
}
return render(request, 'complaint.html', context)
forms.py:
from django import forms
from .models import Complaint
from django.contrib.auth.models import User
class ComplaintForm(forms.ModelForm):
complaint_text = forms.CharField(max_length=1000)
switch_schedule_yes_or_no = forms.BooleanField()
user = forms.ModelChoiceField(queryset=User.objects.all())
class Meta:
model = Complaint
fields = ['complaint_text', 'switch_schedule_yes_or_no', 'user']
If it is possible to somehow design this is a way that allows the complaint to be associated with the authenticated user, that would be amazing! Be it by passing parameters from a view to a form or by using user-individual URLS. I have been trying to solve this for days now.
Cheers!
You can use request.user to access the authenticated user and associate with you Complaint object. You don't need the user field in the ComplaintForm form.
#login_required()
def complaint_view(request):
form = ComplaintForm(request.POST)
if form.is_valid():
complaint = form.save(commit=False) #don't commit to DB
complaint.user = request.user #access the user
complaint.save() # save and commit to DB
form = ComplaintForm()
context = {
'form': form,
}
return render(request, 'complaint.html', context)
Try the following Class Based View Approach
In your form, you can ommit this line:
user = forms.ModelChoiceField(queryset=User.objects.all())
from django.views import generic
from my_app.forms import ComplaintForm
class ComplaintView(generic.CreateView):
template_name = "complaint.html"
form_class = ComplaintForm
def form_valid(self, form):
form.instance.user = self.request.user # This is where what you want happens
super().form_valid(form)
And to add the login required constraint, you can use the LoginRequiredMixin:
from django.contrib.auth.mixins import LoginRequiredMixin
class ComplaintView(LoginRequiredMixin, generic.CreateView):
pass

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 set dynamic initial values to django modelform field

I'm kinda new to django, I need to set a dynamic initial value to my modelform field. I have a database field in my model name 'author' it has a foreignkey that connects it to the django user model. I need to automatically set this to the current user anytime a user fills in information into the form.
from what I gathered about this problem, I'd have to define an __init__ function inside the MyHouseEditForm below, I'm new to django and all the examples I've seen a pretty confusing.
forms.py
from django import forms
from django.contrib.auth.models import User
from .models import Myhouses
class MyHouseEditForm(forms.ModelForm):
class Meta:
model = Myhouses
fields = ('author','name_of_accomodation', 'type_of_room', 'house_rent', 'availability', 'location', 'nearest_institution', 'description', 'image')
i need to set the value of 'author' to the current user anytime a user logs in.
models.py
from django.db import models
from django.contrib.auth.models import User
class Myhouses(models.Model):
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='author')
Available = 'A'
Not_Available = 'NA'
Availability = (
(Available, 'Available'),
(Not_Available, 'Not_Available'),
)
name_of_accomodation = models.CharField(max_length=200)
type_of_room = models.CharField(max_length=200)
house_rent = models.IntegerField(null=True)
availability = models.CharField(max_length=2, choices=Availability, default=Available,)
location = models.CharField(max_length=200)
nearest_institution = models.CharField(max_length=200)
description = models.TextField(blank=True)
image = models.ImageField(upload_to='profile_image')
def __str__(self):
return self.name_of_accomodation
views.py
#login_required
def addlisting(request):
if request.method == 'POST':
form = MyHouseEditForm(request.POST, files=request.FILES)
if form.is_valid():
Houses = form.save(commit=False)
Houses.save()
return redirect('addlisting')
else:
form = MyHouseEditForm()
return render(request, 'houses/addlisting.html', {'form':form })
No need to show author field in form. It would automatically populate with logged in user.
request.user gives you logged in user object. So, you may remove 'author' filed from forms field section and do this:
Houses = form.save(commit=False)
Houses.author = request.user
Houses.save()
I did something like this in the serializer.
I defined a custom create method like this:
class MyhousesSerializer(FlexFieldsModelSerializer):
...
def create(self, validated_data):
validated_data['author'] = self.context['request'].user
newhouse = Myhouses.objects.create(**validated_data)
return newhouse
It shouldn't matter if you use a more regular model serializer.

Can´t save images on Django Model after extending it

I´m having a really hard time with this. I have extended the Django user model. I created a separate app call "userprofile" (i have 2 apps: 'userprofile' and 'Administration') with new models.py:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
profile_image = models.ImageField(upload_to="/perfil/", blank=True, null=True)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user = u)[0])
the urls.py:
urlpatterns = patterns('',
url(r'^perfil/$', 'apps.userprofile.views.user_profile', name= 'perfil'),
)
and a views.py:
# Create your views here.
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.core.context_processors import csrf
from forms import UserProfileForm
from django.contrib.auth.decorators import login_required
#login_required
def user_profile(request):
if request.method == 'POST':
form = UserProfileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('../index')
else:
user = request.user
profile = user.profile
form = UserProfileForm(instance = profile)
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('profile.html', args)
and of course a forms.py:
from django import forms
from models import UserProfile
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout
from crispy_forms.bootstrap import (FormActions, )
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
helper = FormHelper()
helper.form_method = 'POST'
helper.layout = Layout(
'profile_image',
FormActions(Submit('Editar', 'Editar', css_class= 'btn-primary'))
)
def save(self, commit=True):
fact = super(UserProfileForm, self).save(commit=False)
if commit:
fact.save()
return fact
So, what i´m trying to do is to let the user upload an image an let it use it as a profile image. I set the:
AUTH_PROFILE_MODULE = 'apps.userprofile.UserProfile' (the app is inside a folder call 'apps' that´s why the first 'apps' before userprofile)
in the settings.py, and i added the urls of 'userprofile' to the main project. Now I have the template where i can upload an image, the problem is that the image is never saved in the database so I can´t call a function to display the image in a template, let´s say the User Profile page.
Does anyone looking at the code knows what I am doing wrong?
According to the Django 1.7 docs, ModelForm classes must explicitly specify which fields should be updated when the save() method is called. Try adding fields = __all__ to your UserProfileForm class meta.
Relevant section of ModelForm documentation
Notice the first line of the Note in that link:
Any fields not included in a form by the above logic will not be set
by the form’s save() method.
I am still learning Django myself but that's what I would try first. :)

Categories

Resources