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. :)
Related
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.
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
I am creating a registration page for my website using django. The registration form contains the following fields: Username,E-mail,password,password confirmation, user_type. user_type can be either 'student' or 'organisation' which is of radio select type. Depending on the user_type, a user can perform only those specific tasks assigned for that type. So I need a way to store their user_type into the database and later check on it to let them do a specific task. How can I solve this problem?
Forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
USER_TYPE_CHOICES = (
('student', 'Student'),
('organization', 'Organization'),)
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
user_type = forms.ChoiceField(required=True,widget=forms.RadioSelect, choices=USER_TYPE_CHOICES)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2','user_type']
Views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
uType = form.cleaned_data.get('user_type')
messages.success(request, 'Account created for {}, You may login now!'.format(username))
return redirect('TakeTest-Home')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
Models.py is empty for this app.
Since, the choice of that Form field will be one chosen string value, then you can just store that as a charfield in your model:
So, user_type = models.CharField()
If your choices look as they are in your example:
USER_TYPE_CHOICES = (
('student', 'Student'),
('organization', 'Organization'),)
However, you can give integer values to the choices in you Form like:
choices=(
(0,'Student'),
(1,'Organization'),
)
Thus in your model you will save it as user_type = models.IntegerField()
Since only one value (one choice) will be saved at every user, then when you will get this field value back, you will just define tasks and permissions according to the values with if and else in your code later.
And if you would create this Form from Models then you can define the whole thing very similarly in your models, with list of choice' values and so on, but this is not the point of this question.
So your Model simply would look like this for example:
class User(models.Model):
username = models.CharField(max_length=150)
email = models.EmailField(max_length=254)
password1 = models.CharField(max_length=50)
password1 = models.CharField(max_length=50)
user_type = models.CharField(max_length=20)
creation_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.username
And if you would like to, then you can save the submitted Form values directly to the database like this too in your view:
from .forms import UserRegisterForm
from .models import User
# and so on imported
def register(request):
if request.method == 'POST':
username = request.POST.get('username')
email = request.POST.get('email')
password1 = request.POST.get('password1')
password2 = request.POST.get('password2')
user_type = request.POST.get('user_type')
NewUser = User.objects.create(username = username, email = email, password1 = password1, password2 = password2, user_type = user_type)
Try:
NewUser.full_clean(exclude=None, validate_unique=True)
NewerUser.save()
return HttpResponse('')
except ValidationError as e:
# Do something based on the errors contained in e.message_dict.
# Display them to a user, or handle them programmatically.
pass
# you can send back messages here too
return HttpResponse('whatever')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
Of course you can save that with the normal Form saving method as you did in your question, I just did not want to repeat your code from your question.
The point is on your question that you can either save the chosen user_type value as Charfield or you can also save the chosen value as IntegerField in your Model. In the database it will be only one value for every user. And then you can work with that value later.
And a bit clearer, the point is that you can redirect tasks based on the user_type value in any way you want after you have that value in User table at every of your registered users:
def Usertask_sorting(task1, task2, username):
Task1 = task1
Task2 = task2
Username = username
field_name = 'user_type'
obj = User.objects.get(username=Username)
user_type_value = getattr(obj, field_name)
if user_type_value == 'Student':
# let them do task1 or whatever
return redirect('student_form')
elif user_type_value == 'Organization':
# let the user do task2 something else
return redirect('organization_form')
else :
# the user has no valid user_type set
return redirect('profile_form')
I hope this can give you some direction in the question.
UPDATE - JUST GIVING SOME USEFUL SUGGESTIONS ON CUSTOM USER MODEL
Now the above is fine and answer the original question, however I promised to #Kiran that I'll give some additional useful suggestion to his custom user structure. Since in live environment it's not lucky to create a Model named User since Django already has a User Model and thus can cause conflict.
Instead what we do is creating our own User Model from AbstractModel class which is using all the benefits of Django User Model. It's better to try and practice the whole thing in a new Django project!
But before that, we create a userType Model since it's better to have user_types in a table and not hard-coded in our model or form, then later we can add or delete user_types easier. And since we want to use the values of this model for user_type choices in our custom User model:
from django.db import models
class userType(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
Then we just run a migrate and then we continue with the next steps:
With creating our custom User model:
from django.db import models
from django.contrib.auth.base_user import AbstractBaseUser
class OurUser(AbstractUser):
# we get the usertype choice values from the userType table and creating a list of that
all_user_types = userType.objects.values()
USER_TYPE_CHOICES = [(d['id'], d['name']) for d in all_user_types]
chosen_user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES, null=True, verbose_name='User type')
And then we will create our Form from our User Model:
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.forms import AuthenticationForm
from django import forms
from .models import OurUser
class UserRegistration(UserCreationForm):
class Meta:
model = OurUser
fields = ['username', 'email','chosen_user_type',]
And then we create our view for Registration:
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.urls import reverse
from django.views import View
from .models import OurUser
from django.template import loader
from django.contrib.auth import login, authenticate
# from django.contrib.auth.forms import UserCreationForm
from .forms import UserRegistration
from .models import OurUser
def signup(request):
if request.method == 'POST':
form = UserRegistration(request.POST)
if form.is_valid():
# form.save()
username = form.cleaned_data.get('username')
email = form.cleaned_data.get('email')
raw_password = form.cleaned_data.get('password1')
chosen_user_type = form.cleaned_data.get('chosen_user_type')
newUser = OurUser.objects.create_user(username=username, email=email, password=raw_password, chosen_user_type=chosen_user_type)
newUser.save()
# user = authenticate(email=email, password=raw_password) # authenticate not needed here
login(request, user)
return HttpResponseRedirect(reverse('myappname:index'))
else:
form = UserRegistration()
return render(request, 'myappname/signup.html', {'form': form})
And at the end we do not have to forget to register our models in admin.py
from django.contrib import admin
from .models import OurUser, userType
# Register your models here.
admin.site.register(OurUser)
admin.site.register(userType)
And also we do not have to forget to define our custom User Model authentication in settings.py
AUTH_USER_MODEL = 'myappname.OurUser'
In the urls.py we have to give a url path to our registration Form like:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('signup', views.signup, name='signup'),
]
And the signup.html in our templates folder:
{% extends 'myappname/base.html' %}
{% block content %}
<h2>Sign up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign up</button>
</form>
{% endblock %}
And finally we just have to run migrate and we should go to our admin of our site and create some user type in our userType table which user types will be used in our custom registration Form as choices.
So I hope it's clearing this subject more. Then we have to figure out the permissions and so on connected to our user types too. Cheers. ;)
First you need to know that choices are just Many to Many field in the django.
So you need to declare it in models.py.It should be like below:
class Choices(models.Model):
description = models.CharField(max_length=100)
class UserProfile(models.Model):
user = models.ForeignKey(User, blank=True, unique=True, verbose_name='profile_user')
choices = models.ManyToManyField(Choices)
def __unicode__(self):
return self.name
Now you can change your form.py according to it.
In the views.py save the form data like below:
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Account created for {}, You may login now!'.format(username))
return redirect('TakeTest-Home')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
I hope it will help.
I got stuck with small issue in django project, I hope I can get some good answers here.
I have added user profile inline form with django User form by doing code like this:
from django.core.exceptions import ValidationError
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.contrib.auth.models import User
from djangocalendar.models import UserProfile
from tableapp.models import *
from djangocalendar.models import *
from django import forms
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = True
verbose_name_plural = 'profile'
class MyUserChangeForm(UserChangeForm):
def clean_first_name(self):
if self.cleaned_data["first_name"].strip() == '':
raise ValidationError("First name is required.")
return self.cleaned_data["first_name"]
def clean_last_name(self):
if self.cleaned_data["last_name"].strip() == '':
raise ValidationError("Last name is required.")
return self.cleaned_data["last_name"]
# Define a new User admin
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
inlines = UserProfileInline,
# Register your models here
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
Issue I am facing with this, This inline appears with User Add form and with Change user form too. I don't want it to display while adding user.
Like In this screenshot: Inline form appears with add User form! I don't want this to add inline form here. But I want to display inline form while editing user with other forms like personal form, information form.
I have found solution
Define a new User admin
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
inlines = UserProfileInline,
def get_inline_instances(self, request, obj=None):
if not obj:
return list()
return super(MyUserAdmin, self).get_inline_instances(request, obj)
I would like to create a mutli-step form in Django that only submits the data for processing at the end of all the steps. Each step needs to be able to access and display data that we entered in previous step(s).
Is there a way to do this with Django? Django's Form-Wizard can't handle this basic functionality.
Of course there's a way to do this in Django.
One way is to hold your values in session until you submit them at the end. You can populate your forms using values held in session if you return to previous step.
With some searching, you may find an app that someone has already written that will do what you want, but doing what you need isn't hard to do with Django, or any other framework.
Example, ignoring import statements:
#models/forms
class Person(models.Model):
fn = models.CharField(max_length=40)
class Pet(models.Model):
owner = models.ForeignKey(Person)
name = models.CharField(max_length=40)
class PersonForm(forms.ModelForm):
class Meta:
model = Person
class PetForm(forms.ModelForm):
class Meta:
model = Pet
exclude = ('owner',)
#views
def step1(request):
initial={'fn': request.session.get('fn', None)}
form = PersonForm(request.POST or None, initial=initial)
if request.method == 'POST':
if form.is_valid():
request.session['fn'] = form.cleaned_data['fn']
return HttpResponseRedirect(reverse('step2'))
return render(request, 'step1.html', {'form': form})
def step2(request):
form = PetForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
pet = form.save(commit=False)
person = Person.objects.create(fn=request.session['fn'])
pet.owner = person
pet.save()
return HttpResponseRedirect(reverse('finished'))
return render(request, 'step2.html', {'form': form})
We'll assume that step2.html has a link to go back to step1.html.
You'll notice in the step1 view I'm pulling the value for fn from session that was set when the form was saved. You would need to persist the values from all previous steps into the session. At the end of the steps, grab the values, create your objects and redirect to a finished view, whatever that might be.
None of this code has been tested, but it should get you going.
You can easily do this with the form wizard of django-formtools. A simple example would be something like the following.
forms.py
from django import forms
class ContactForm1(forms.Form):
subject = forms.CharField(max_length=100)
sender = forms.EmailField()
class ContactForm2(forms.Form):
message = forms.CharField(widget=forms.Textarea)
views.py
from django.shortcuts import redirect
from formtools.wizard.views import SessionWizardView
class ContactWizard(SessionWizardView):
def done(self, form_list, **kwargs):
do_something_with_the_form_data(form_list)
return redirect('/page-to-redirect-to-when-done/')
urls.py
from django.conf.urls import url
from forms import ContactForm1, ContactForm2
from views import ContactWizard
urlpatterns = [
url(r'^contact/$', ContactWizard.as_view([ContactForm1, ContactForm2])),
]