In my django app I have a User model that has a Boolean field of is_manager.
User model in models.py:
class User(AbstractUser):
name = models.CharField(max_length=15, null=True, blank=True)
last_name = models.CharField(max_length=15, null=True, blank=True)
title = models.CharField(max_length=50, null=True, blank=True)
email = models.EmailField(unique=True)
bio = models.TextField(null=True, blank=True)
company = models.ForeignKey(Company, on_delete=models.DO_NOTHING, null=True)
is_manager = models.BooleanField(default=False)
can_assign = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
I've been trying to create an edit page in order for managers and users to be able to change some of their fields.
Regular users should be able to change their bio and title, and the managers can change the can_assign Boolean.
I have a form that deals with the logic of that in forms.py:
class EditUserForm(ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
if self.user.is_manager:
super().__init__(**kwargs)
else:
super().__init__(**kwargs)
del self.fields['can_assign']
class Meta:
model = User
fields = ['title', 'can_assign', 'bio']
views.py:
#login_required
def editUser(request, pk):
user = User.objects.get(id=pk)
if request.user.is_manager or request.user == user:
#POST
if request.method == 'POST':
form = EditUserForm(request.POST, instance=user, user=request.user)
if form.is_valid():
form.save()
redirect('user-page', pk)
else:
print('nope')
#GET
form = EditUserForm(user=request.user, instance=user)
context = {'user': user, 'form': form}
return render(request, 'users/user_edit.html', context)
else:
return HttpResponse('<h1>Access Denied</h1>')
template:
{% extends 'main.html' %}
{% block content %}
<form method="POST" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Submit">
</form>
{% endblock content %}
for some reason the form.is_valid() method returns False. I have no idea why.
I have tried to use the .errors method on the form and on the form fields. No errors shown.
Thanks for any help!
" Oh! I completely missed that. I think the *args is required because that's how you pass in the request.POST. if you would have an explicit key like myform(data=request.POST) it would have worked because it would be in the *kwargs .. So it was basically failing cause it was acting like you were just initiating a new form, not submitting one –
Nealium
"
Related
I'm trying to make a registration page for my project. Standard model User is not enough for me, so I created another model named Profile:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
sex = models.CharField(max_length=1, choices=SEX_CHOICES, default='М',
verbose_name='Пол')
third_name = models.CharField(max_length=30, verbose_name='Отчество')
grade = models.CharField(max_length=2, choices=GRADE_CHOICES, default='1',
verbose_name='Класс обучения')
age = models.PositiveSmallIntegerField(default=7, verbose_name='Возраст',
validators=[
MaxValueValidator(100),
MinValueValidator(4)
]
)
school = models.ForeignKey(School, on_delete=models.PROTECT,
verbose_name='Учебное заведение',
blank=True, null=True, default=None)
interest = models.ManyToManyField(OlympiadSubject,
verbose_name='Интересующие предметы')
On both User and Profile I created a ModelForm:
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('third_name', 'sex', 'grade', 'age', 'school', 'interest')
And wrote a view for registration:
def create_profile(request):
if request.method == 'POST':
user_form = UserForm()
profile_form = ProfileForm()
if user_form.is_valid() and profile_form.is_valid():
User.objects.create(**user_form.cleaned_data)
Profile.objects.create(**profile_form.cleaned_data, user=User)
return redirect('/login')
else:
profile_form.add_error('__all__', 'Данные введены неверно!')
else:
user_form = UserForm()
profile_form = ProfileForm()
return render(request, 'users/profile_create.html', {
'user_form': user_form,
'profile_form': profile_form
})
and of course I have a template for that:
{% extends 'main/layout.html' %}
{% block title %} Some text {% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<button type="submit">Сохранить изменения</button>
</form>
{% endblock %}
but i get the same error every time:
ProfileForm object has no attribute cleaned_data
Don't know how to fix it.
This is my first question on stackoverflow. Sorry, if I wrote something incorrect.
When you define the forms in case of POST request, you don't bind the data to the forms. Since the forms you have created are empty, there is no cleaned_data.
Try
if request.method == 'POST':
user_form = UserForm(request.POST) # the request.POST part binds the data to the form
profile_form = ProfileForm(request.POST)
You are missing to capture the form data that are coming with the POST request.
You may write:
if request.method == 'POST':
user_form = UserForm(request.POST)
profile_form = ProfileForm(request.POST)
I am rendering a form and when I am submitting that form getting this error
IntegrityError at /business/
NOT NULL constraint failed: app_business.user_id
models.py
class business(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=400)
rate_it = models.BooleanField(default=False)
availibility = models.BooleanField(default=True)
def __str__(self):
return self.name
forms.py
class businessform(forms.ModelForm):
class Meta:
model = business
fields = ['name', 'rate_it', 'availibility']
views.py
def formview(request):
if request.method == 'POST':
form = businessform(request.POST)
if form.is_valid():
form.save()
return HttpResponse('saved')
else:
form = businessform
return render(request, 'business.html', {'form':form})
html file
<form method="POST" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" name="submit">
</form>
I don't know why this error is coming.
When you are saving the form you haven't passed any user object. Either pass user object while saving the form or make the user field null=True, blank=True in your model.
user = models.ForeignKey(User, null=True, blank=True)
EDIT
Create an user object and save it first. Then pass that instance in the form to update values you got from template. Then save the form.
user = User.objects.create_user(username=username, password=password)
user.save()
obj = business.objects.create(user=user, name="")
form = form = businessform(request.POST, instance=obj)
if form.is_valid():
form.save()
return HttpResponse('saved')
Be careful about the usernames. Usernames must be unique. So, you need to generate those.
I have created this application but the problem I face now is one that has kept me up all night. I want users to be able to see and select only their own categories when they want to create a post. This is part of my codes and additional codes would be provided on request
category model
class Category(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1,related_name='categories_created')
name = models.CharField(max_length = 120)
slug = models.SlugField(unique= True)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
post model
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1,related_name='posts_created') #blank=True, null=True)
title = models.CharField(max_length = 120)
slug = models.SlugField(unique= True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category_created', null= True)
addition codes would be provided immediately on request. Thanks
View.py in post app
def create(request):
if not request.user.is_authenticated():
messages.error(request, "Kindly confirm Your mail")
#or raise Http404
form = PostForm(request.POST or None, request.FILES or None)
user = request.user
categories = Category.objects.filter(category_created__user=user).distinct()
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
create_action(request.user, 'Posts', instance)
messages.success(request, "Post created")
return HttpResponseRedirect(instance.get_absolute_url())
context = {
"form": form,
}
template = 'create.html'
return render(request,template,context)
Form
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = [
"title",
"content",
"category",
]
html
{% if form %}
<form method="POST" action="" enctype="multipart/form-data">{% csrf_token %}
{{ form|crispy|safe }}
<input type="submit" name="submit" value="Publish">
</form>
{% endif %}
What you need to do is well-described here. Basically, you are using ModelForm which generates the form from your model. Your model doesn't know anything about filtering by user, so you will need to explicitly add a QuerySet to your form that only shows the desired categories. Change your "categories = ..." line to something like:
form.category.queryset = Category.objects.filter(user=user)
form.fields['category'].queryset = Category.objects.filter(user=user)</strike>
I am new to Django and need a help.
I want to allow users to update their account data using form, but struggle with associating Django User model with my UserProfile model, which extends default model with some additional fields.
I found, that solution is to create my own model form, but unfortunately I'm not exactly sure how to implement it.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=100, default='')
city = models.CharField(max_length=100, default='')
website = models.URLField(default='')
phone = models.IntegerField(default=0)
image = models.ImageField(upload_to='profile_image', blank=True)
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
forms.py:
class EditProfileForm(UserChangeForm):
image = forms.ImageField(required=False)
city = forms.CharField(required=False)
class Meta:
model = User
fields = (
'email',
'first_name',
'last_name',
'password',
'image',
'city'
)
views.py:
def edit_profile(request):
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect(reverse('accounts:view_profile'))
else:
form = EditProfileForm(instance=request.user)
args = {'form': form}
return render(request, 'accounts/edit_profile.html', args)
edit_profile.html:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
You are looking for Inline formsets. Just read the docs, it's pretty simple.
I'm using Pinax to create a new project. For this project I needed to create a new app 'Business' which is much like Profiles but they wanted to keep everything seperate for Businesses.
I'm trying to have the admin be able to change the logo or "avatar" for the business profile. Im using the ImageModel class from Photologue to control the image upload, etc but I ran into a problem. When going through the form, the form goes through and redirects but the image doesn't actually get updated. When you go through the django admin, the image uploads fine.
If someone could take a look and see if something is missing, I've been staring at it for too long, so I need a fresh pair of eyes.
Business Models.py
class Business(models.Model):
name = models.CharField(verbose_name="Name", max_length=140)
desc = models.TextField(verbose_name="Description", null=True, blank=True)
bus_type = models.CharField(verbose_name="Business Type", choices=BUSINESS_TYPES, max_length=20)
location = models.CharField(_("location"), null=True, blank=True, max_length=200)
website = models.URLField(_("website"), null=True, blank=True, verify_exists=False)
created_by = models.ForeignKey(User, related_name="Created By")
admin = models.ManyToManyField(User, related_name="Admin User", null=True, blank=True)
followers = models.ManyToManyField(User, related_name="Followed by", null=True, blank=True)
date_added = models.DateField(verbose_name="Date Added")
class Meta:
verbose_name = "Business"
verbose_name_plural = "Businesses"
def __unicode__(self):
return self.name
class BusinessLogo(ImageModel):
business = models.ForeignKey(Business, related_name="Business Association")
My views.py
#login_required
def changeLogo(request, bus_id):
user = request.user
b = get_object_or_404(Business, pk = bus_id)
if request.method == 'POST':
form = ChangeLogoForm(request.POST, request.FILES, instance = b)
if form.is_valid():
biz_logo = form.save(commit=False)
biz_logo.save()
return HttpResponseRedirect('/')
else:
form = ChangeLogoForm()
return render_to_response('business/changelogo.html',
{'user': user, 'form':form, 'b':b}, context_instance=RequestContext(request))
Forms.py
class ChangeLogoForm(ModelForm):
class Meta:
model = BusinessLogo
def save(self, force_insert=False, force_update=False, commit=True):
f = super(ChangeLogoForm, self).save(commit=False)
if commit:
f.save()
print "form save method was called with commit TRUE"
return f
And finally my changelogo.html
...
{% block body %}
<h1>Change Logo</h1>
<form method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Upload">
</form>
{% endblock %}
...
Thanks everyone, for taking a look.
Steve
The ChangeLogoForm's model is BusinessLogo, but when calling it's constructor you pass it a Business instance:
b = get_object_or_404(Business, pk = bus_id)
...
form = ChangeLogoForm(request.POST, request.FILES, instance = b)
(And you should probably use a OneToOneField field instead of ForeignKey)