django updating user profile with custom form + display group name - django

I've got 2 questions:
1) I'm displaying a list of users w/ their group,and for the group name I got: ]> using {{instance.groups.all}} in my template. Any ideas to have only mygroup displayed?
2) For my update user form, I got an error and I don't know how and where to resolve it.
error: updateUserView() got an unexpected keyword argument 'id'
forms.py
class UpdateForm(UserChangeForm):
is_active = forms.BooleanField()
Group = [('Viewers', 'Viewers'), ('Editors', 'Editors'), ('Creators', 'Creators'), ]
group_name = forms.ChoiceField(choices=Group)
class Meta:
model = User
fields = ('email', 'is_active', 'group_name', )
views.py
def updateUserView(request):
if request.method == 'POST':
form = UpdateForm(request.POST, instance=request.user)
if form.is_valid():
user = form.save()
group = Group.objects.get(name=request.POST.get('group_name'))
user.groups.add(group)
return redirect('accounts:users')
else:
form = UpdateForm(instance=request.user)
return render(request, 'accounts/update_user.html', {'form': form})
class UserView(LoginRequiredMixin, GroupRequiredMixin, ListView):
template_name = 'accounts/display_users.html'
group_required = ['Creators']
queryset = User.objects.filter(is_active=True)

instead of using
group = Group.objects.get(name=request.POST.get('group_name'))
try using
group = form.cleaned_data.get('Group')

To solve the error error: updateUserView() got an unexpected keyword argument 'id'
you need to pass the id to the view. Because your url is probably like this '/user/<int:id>/'
def updateUserView(request, id):
if request.method == 'POST':
........

Related

Cannot assign "<SimpleLazyObject: <User: JohnDoe12>>": "Profile.user" must be a "User" instance

I have two models
class User(auth.models.User,auth.models.PermissionsMixin):
def __str__(self):
return "#{}".format(self.username)
class Profile(models.Model):
user = models.OneToOneField(User,default=None,
null=True,on_delete=models.CASCADE,)
name = models.CharField(max_length=128) #actual creator's name
In the forms.py
class ProfileForm(forms.ModelForm):
class Meta:
exclude = ['user']
# fields = '__all__'
model = models.Profile
In views.py
def TestPage(request):
form = ProfileForm
if request.method == "POST":
form = ProfileForm(request.POST)
if form.is_valid():
form_instance=form.save(commit=False)
form_instance.user = request.user
form_instance.save()
return render(request,'test.html')
else:
print('ERROR FORM INVALID')
return render(request,'accounts/update_profile.html',{'form':form})
I think there is an issue with the line form_instance.user = request.user. I am getting an errorCannot assign ">": "Profile.user" must be a "User" instance. To Profile.user I want save current user. could someone help me with this? Thanks.
Try this
form_instance.user = request.user.pk
If not work then add your models.py
Maybe you can try like this:
form_instance.user = User.objects.get(pk=request.user.pk)
But also make sure that user is logged in before coming to this line(Like using #login_required or LoginRequiredMixin).

I am getting the following error when trying to save this form

Here is the error: Any help in undestanding what is happening and how to fix it would be much appreciated
Cannot assign '<PartnerForm bound=True, valid=True, fields=(name;logo;banner_image;mission;vision;website_link;fb_link;twitter_link;ig_link)>': "Product.partner" must be a "Partner" instance.
I am trying to add a one to many relationship between two models. The 'one' model is a 'Partner. The 'many' are 'Product' which contain image description, price, etc.
Here are my views.py
def partner_create(request):
#Trying to add multiple product functionality
if not request.user.is_staff or not request.user.is_superuser:
raise Http404
ProductFormSet = inlineformset_factory(Partner, Product, form=ProductForm, extra=3)
if request.method == 'POST':
partnerForm = PartnerForm(request.POST or None, request.FILES or None)
formset = ProductFormSet(request.POST, request.FILES, queryset=Product.objects.none())
if partnerForm.is_valid() and formset.is_valid():
instance = partnerForm.save(commit=False)
instance.save()
for form in formset.cleaned_data:
image = form['image']
product = Product(partner=partnerForm, image=image)
product.save()
messages.success(request, "Partner Successfully Created")
else:
print partnerForm.errors, formset.errors
else:
partnerForm = PartnerForm()
formset = ProductFormSet(queryset=Product.objects.none())
return render(request, "partner_form.html", {"partnerForm": partnerForm, "formset": formset})
here is my admin.py
class ProductImageInline(admin.TabularInline):
model = Product
extra = 3
#This works originally but doesn't do multiple products
class PartnerModelAdmin(admin.ModelAdmin):
list_display = ["__unicode__", "timestamp"]
inlines = [ProductImageInline,]
class Meta:
model = Partner
admin.site.register(Partner, PartnerModelAdmin)
Here is my form.py
class PartnerForm(forms.ModelForm):
mission = forms.CharField(widget=PagedownWidget(show_preview=False))
vision = forms.CharField(widget=PagedownWidget(show_preview=False))
# publish = forms.DateField(widget=forms.SelectDateWidget)
class Meta:
model = Partner
fields = [
"name",
"logo",
"banner_image",
"mission",
"vision",
"website_link",
"fb_link",
"twitter_link",
"ig_link",
]
class ProductForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Product
fields = [
"partner",
"image",
"description",
"price"
]
The error is pretty obvious. In the lines
product = Product(partner=partnerForm, image=image)
product.save()
you are assigning a PartnerForm to your product while it expects a Partner instance! Change it to
product = Product(partner=instance, image=image)
product.save()
(instance is a Partner instance from what I see above) and it will work.

"Select a valid choice. <choice> is not one of the available choices" error when submitting ManyToMany ModelForm

I want to limit the choices of a ManyToManyField to those matching a ForeignKey. The form displays properly, but upon saving results in an error Select a valid choice. <choice> is not one of the available choices.
Before I was trying to limit the queryset by passing a parameter in the view to the form, and then using that parameter to filter the queryset.
Models:
class VenueEventTimeslot(models.Model):
venue = models.ForeignKey(Venue)
name = models.CharField(max_length=255)
class VenueEvent(models.Model):
venue = models.ForeignKey(Venue)
event_timeslots = models.ManyToManyField(VenueEventTimeslot)
class VenueEventForm(ModelForm):
event_timeslots = ModelMultipleChoiceField(queryset=None, widget=CheckboxSelectMultiple())
def __init__(self, *args, **kwargs): # limit timeslots to those of the venue only
venue_obj = kwargs.pop('venue_obj',None)
super(VenueEventForm, self).__init__(*args,**kwargs)
self.fields['event_timeslots'].queryset=VenueEventTimeslot.objects.filter(venue=venue_obj)
class Meta:
model = VenueEvent
fields = ['event_timeslots']
Views:
#login_required
def calendar(request, pk):
venue = Venue.objects.get(pk = pk)
if request.method == "POST":
form = VenueEventForm(request.POST)
if form.is_valid():
# form stuff
else:
form = VenueEventForm(venue_obj = venue)
context = {'venue':venue, 'form':form}
return render(request, ... , context)
However, if I pass the queryset from the view, it works perfectly.
Models:
class VenueEventTimeslot(models.Model):
# same as above
class VenueEvent(models.Model):
# same as above
class VenueEventForm(ModelForm):
class Meta:
model = VenueEvent
fields = ['date','client_name','event_timeslots']
widgets = {
'date': SelectDateWidget(),
'event_timeslots': CheckboxSelectMultiple(),
}
Views:
#login_required
def calendar(request, pk):
venue = Venue.objects.get(pk = pk)
if request.method == "POST":
form = VenueEventForm(request.POST)
if form.is_valid():
# form stuff
else:
form = VenueEventForm()
form.fields['event_timeslots'].queryset=VenueEventTimeslot.objects.filter(venue=venue)
context = {'venue':venue, 'form':form}
return render(request, ..., context)
Would anyone be able to shed some light on this?
I just solved a problem similar to this yesterday which is right here, How To Exclude A Value In A ModelMultipleChoiceField?, but I think the issue with your init function is the way it is formatted. Instead of venue=venue_obj, you need to change it to pk=venue_obj because it appear you are getting the pk of venue in the view instead of the venue attribute of VenueEvent , and I reformatted your form a bit to make it look cleaner.
forms.py
class VenueEventForm(ModelForm):
def __init__(self, *args, **kwargs): # limit timeslots to those of the venue only
venue_obj = kwargs.pop('venue_obj')
super(VenueEventForm, self).__init__(*args,**kwargs)
self.fields['event_timeslots'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=VenueEventTimeslot.objects.filter(pk=venue_obj))
class Meta:
model = VenueEvent
fields = ['event_timeslots']
views.py
#login_required
def calendar(request, pk):
venue = Venue.objects.get(pk = pk)
if request.method == "POST":
form = VenueEventForm(request.POST, venue_obj=venue)
if form.is_valid():
# form stuff
else:
print VenueEventForm.errors
else:
form = VenueEventForm(venue_obj=venue)
context = {'venue':venue, 'form':form}
return render(request, ... , context)

Django model doesn't relate itself to User through ForeignKey

my question is about modelforms, models and instances. After doing some troubleshooting I think my problem is that either the user field from UserFile doesn't associate itself to the auth.User or that the modelform doesn't pass the instance of auth.User. The error is at the dynamic pathing - file_destination - when I try self.user it can't find the user :/
# Model
class UserFile(models.Model):
user = models.ForeignKey('auth.User', related_name='user_file', primary_key=True, unique=True)
user_file = models.FileField(upload_to=file_destination, null=True)
def __unicode__(self):
return self.user_file.name
# View
def login_index(request):
template = 'loginIndex.html'
context = Context()
if request.user.is_authenticated():
if request.method == 'POST':
form = UserUpload(request.POST, request.FILES, instance=request.user)
context.update({'form': form})
if form.is_valid() and form.is_multipart():
instance = UserFile(user_file=request.FILES.get('user_file'))
instance.save()
else:
form = UserUpload()
context.update({'form': form})
return render(request, template, context)
else:
return render(request, template, context)
# Form
class UserUpload(ModelForm):
user_file = forms.FileField(required=False, widget=forms.ClearableFileInput, label='Upload')
class Meta:
model = UserFile
fields = ['user_file']
def clean_user_file(self):
check_user_file = self.cleaned_data.get('user_file')
if check_user_file:
if check_user_file.size > 5120000:
raise ValueError('File is too big for upload')
return check_user_file
# The problem arises when I submit the instance, which saves the file from the form to upload_to=file_destination
# In file_destination I get an error on self.user.username saying || DoesNotExist at "" UserFile has no user.
# My self.user is an None object.
def file_destination(self, filename):
filename = name_generator()
url = "%s/%s/%s" % (self.user.username, 'uploads' ,filename)
return url
You need to manually set the user field on your UserFile instance:
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instanve.save()
form.save_m2m() # add this if you add m2m relationships to `UserFile`
Also, it is a good idea to redirect after the form handling succeeds:
from django.shortcuts import redirect
# ...
return redirect("view-name")

django forms - how to filter number of available options in a form

I'm trying to limit number of "categories" that user have available when entering new "feed" only to categories that he owns and he created. The way it works now is that user can add "feed" to other users' "categories" as this is what the form displays. How can I fix it ?
thanks!
-M
models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User)
class Feed(models.Model):
url = models.URLField()
name = models.CharField(max_length=50)
created = models.DateTimeField(auto_now_add=True)
description = models.TextField(blank=True)
category = models.ForeignKey(Category)
user = models.ForeignKey(User)
forms.py
class FeedForm(forms.ModelForm):
class Meta:
model = Feed
exclude = ['user']
views.py
def addfeed(request, user):
user = request.user
page_title = "Add feed"
instance = Category.objects.filter(user=request.user)
if request.method == 'POST':
form = FeedForm(request.POST, instance=instance)
if form.is_valid():
feed = form.save(commit=False)
feed.user = request.user
feed.save()
return HttpResponseRedirect("/user/" + user.username + "/manage")
else:
form = FeedForm()
return render(request, "form_manage.html", {
'page_title': page_title,
'form': form,
})
Set the queryset attribute of the field somewhere. Because it depends on your user, it's something you have to set during or after instantiating the form. For instance, here's how to do it in the view:
def addfeed(request, user):
user = request.user # why does this view take user as an arg and then reassign?
page_title = "Add feed"
categories = Category.objects.filter(user=request.user)
if request.method == 'POST':
form = FeedForm(request.POST)
form.fields['category'].queryset = categories
if form.is_valid():
feed = form.save(commit=False)
feed.user = request.user
feed.save()
return HttpResponseRedirect("/user/" + user.username + "/manage")
else:
form = FeedForm()
form.fields['category'].queryset = categories
return render(request, "form_manage.html", {
'page_title': page_title,
'form': form,})
I removed the instance argument to your POST case's form construction because that's meant for passing in an existing Feed instance, not a categories queryset.
You could also do this in the form's __init__ if you pass in the correct categories queryset.
I use javascript to do this. For example, you could pass a list of the relevant categories as extra context in your view then use javascript in your template to empty the pre-populated option field in the form and replace it with your extra context.