As the title states, I am unable to limit the choices of a form field based on a specific user. For example, in the choices for the enrolled field of the form all “riders” are selectable to all “users”, rather than just the “riders” that are “owned” by the user.
I’ve tried this question and answer that essentially asks the same question, as well as some other possible solutions that deal with m2m model fields, limit_choices_to, but have not been successful.
Any advise would be greatly appreciated.
models.py
class Event(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=200, null=True)
description = models.TextField(max_length=255, null=True, blank=True)
start = models.DateTimeField(null=True, blank=True)
end = models.DateTimeField(null=True, blank=True)
enrolled = models.ManyToManyField('riders.Rider',
related_name='events', blank=True)
def __str__(self):
return self.title
model.py (different app)
class Rider(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
birthdate = models.DateField(verbose_name=None, auto_now=False)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.last_name + ', ' +self.first_name
views.py
#login_required
def enroll(request, event_id):
event = Event.objects.get(id=event_id)
if request.method != 'POST':
form = EventForm(instance=event)
else:
form = EventForm(instance=event, data=request.POST)
if form.is_valid():
enroll = form.save(commit=False)
enroll.save()
form.save_m2m()
return HttpResponseRedirect(reverse('riding_schedule:view_events'))
forms.py
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['title', 'start', 'end', 'enrolled']
labels = {'text':''}
widgets = {
'enrolled': forms.CheckboxSelectMultiple()
}
You can try like this:
First, send the current user information to the Form when form is initiated:
#login_required
def enroll(request, event_id):
event = Event.objects.get(id=event_id)
if request.method != 'POST':
form = EventForm(instance=event, user=request.user) # <-- Here
else:
form = EventForm(instance=event, data=request.POST)
# ....
Then use this information in the Form like this:
class EventForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(EventForm, self).__init__(*args, **kwargs)
if user:
self.fields['enrolled'].queryset = Rider.objects.filter(owner=user) # overriding the queryset for enrolled here
class Meta:
model = Event
fields = ['title', 'start', 'end', 'enrolled']
labels = {'text':''}
widgets = {
'enrolled': forms.CheckboxSelectMultiple()
}
Related
I have a template where i should have 2 forms and update them, I succeded to get the 2 foms in the same template, but when i make changes nothing happens !
forms.py
class OrderManageForm(forms.ModelForm):
class Meta:
model = Order
fields = ['customer', 'product', 'quantity', 'status']
class CustomerForm(forms.ModelForm):
address = forms.CharField(widget=forms.Textarea(attrs={'rows': 5}))
class Meta:
model = Customer
fields = ['full_name', 'address', 'phone', 'city', 'email'
models.py
class Customer(models.Model):
full_name = models.CharField(max_length=150)
address = models.CharField(max_length=1500, null=True)
phone = models.CharField(max_length=20)
city = models.CharField(max_length=100)
email = models.EmailField(null=True)
def __str__(self):
return self.full_name
class Order (models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE,)
quantity = models.IntegerField(default=1)
status = models.TextField(choices=ORDER_STATUS, default='Pending')
def __str__(self):
return 'Order n°: ' + str(self.id)
views.py
def update_order(request, order_id):
order = get_object_or_404(Order, id=order_id)
cust = get_object_or_404(Customer, order__id=order_id)
if request.method == 'POST':
customer = CustomerForm(request.POST)
form = OrderManageForm(request.POST)
print(request.POST)
if form.is_valid() and customer.is_valid():
order = form.save(commit=False)
customer = customer.save()
order.customer = customer
order.save()
return redirect('orders')
else:
form = OrderManageForm(instance=order)
customer = CustomerForm(instance=cust)
return render(request, 'dashboard/order_details.html', {'form': form, 'customer': customer})
I put the 2 forms in only one form tag inside my HTML template
You need to feed the instances to the forms such that the forms can update the corresponding records:
def update_order(request, order_id):
order = get_object_or_404(Order, id=order_id)
cust = order.customer
if request.method == 'POST':
customer = CustomerForm(request.POST, instance=cust)
form = OrderManageForm(request.POST, instance=order)
if form.is_valid() and customer.is_valid():
form.save()
customer.save()
return redirect('orders')
# …
You should only redirect in case the two forms are valid, otherwise you can not see the errors that appear on the form. Furthermore you shoudld remove the customer from the fields of the OrderManageForm:
class OrderManageForm(forms.ModelForm):
class Meta:
model = Order
fields = ['product', 'quantity', 'status'] ← no customer
I extended the Django AbstratUser so that users can use email to sign in and signup, these work perfectly. The problem I am facing, however, is that the extra information on the extended model is not storing the information in the database, even though the user gets created. Once I hit the submit button, the user and extended model get created, and while the user model stores the information, the extended model is always empty.
I have tried using both signals and #transaction_atomic, yet, I have not been able to figure it out. Maybe I am missing out something, I do not know.
Models.py
class Company(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
name= models.CharField(_('Company name'), max_length=250)
...
#more information
...
class Meta:
verbose_name = _('Company')
verbose_name_plural = _('Companies')
def __str__(self):
return self.name
forms.py
class CompanySignUpForm(CustomUserCreationForm):
name = forms.CharField(widget=TextInput(attrs={'placeholder': 'Company name'}))
...
#more fields
...
class Meta(CustomUserCreationForm.Meta):
model = User
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_company = True
user.save()
company = Company.objects.create(user=user)
company.name = self.cleaned_data.get('name')
...
#more information
...
return user
Views.py
def company_signup(request):
if request.method == 'POST':
form = CompanySignUpForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'accounts/templates/company_success.html')
else:
form = CompanySignUpForm()
return render(request, 'accounts/templates/company_signup.html', context={
'title': _('Create a Company Account'),
'form': form,
})
Edit:
Thanks to #Mandrup, I was able to extend his solution to fit my need.
forms.py
class CompanySignUpForm(CustomUserCreationForm):
name = forms.CharField(widget=TextInput(attrs={'placeholder': 'Company name'}))
number_of_employees = forms.CharField(widget=NumberInput(attrs={'placeholder': 'Number of employees'}))
phone = forms.CharField(widget=TextInput(attrs={'placeholder': 'Contact Number'}))
country = forms.ModelChoiceField(queryset=Country.objects.all(), required=True, empty_label="Country")
class Meta(CustomUserCreationForm.Meta):
model = User
#transaction.atomic
def save(self, commit=True):
user = super(CompanySignUpForm, self).save(commit=False)
if commit:
user.is_company = True
user.save()
name = self.cleaned_data.get('name')
number_of_employees = self.cleaned_data.get('number_of_employees')
phone = self.cleaned_data.get('phone')
country = self.cleaned_data.get('country')
company = Company(user=user, name=name, number_of_employees=number_of_employees, phone=phone, country=country)
company.save()
return user
Edit:
This worked for me when i tried to create an extended user profile. I changed it to fit your needs.
Model:
class Company(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
name= models.CharField(max_length=250)
...
#more information
...
def __str__(self):
return self.name
Form:
class RegisterUserForm(UserCreationForm):
class Meta:
model = User
fields = ["username", "email", "password1", "password2"]#add whatever fields you want to here
def save(self, commit=True):
user = super(RegisterUserForm, self).save(commit=False)
if commit:
user.save()
company = Company(user=user, name='Company name')
company.save()
return user
I have a question concerning a new project I'm creating. To put it simply, the website has user accounts, and each user has the ability to create a simple paragraph. The form is functioning perfectly, but I can't seem to assign the user's ID to the saved form.
model.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
class Thoughts(models.Model):
user = models.ForeignKey(UserProfile, null=True)
title = models.CharField(max_length=150, default='')
description = models.CharField(max_length=5000, default='')
forms.py
class ThoughtForm(ModelForm):
class Meta:
model = Thoughts
fields = ['title', 'description']
views.py
#login_required(login_url='sign_in')
def add_thought(request):
context = {}
populateContext(request, context)
user_details = UserProfile.objects.get(user=request.user)
context.update(user_details=user_details)
if request.method == 'POST':
new_thought_form = ThoughtForm(request.POST)
if new_thought_form.is_valid():
new_thought_form.save()
return HttpResponse('Hurray, saved!')
else:
new_thought_form = ThoughtForm()
c = {'new_thought_form': new_thought_form,}
c.update(csrf(request))
return render_to_response('lala/add_new_thought.html', c)
Whenever I try adding "instance=user_details.id", it says that the 'int' object has no attribute '_meta'. Any thoughts?
You can simplify the models by removing the UserProfile model:
# models.py
class Thoughts(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=150, default='')
description = models.CharField(max_length=5000, default='')
Your forms.py looks good.
Change your views:
# views.py
#login_required(login_url='sign_in')
def add_thought(request):
if request.method == 'POST':
form = ThoughtForm(request.POST)
if form.is_valid():
thought = form.save(commit=False)
thought.user = request.user
thought.save()
return HttpResponse('Hurray, saved!')
else:
form = ThoughtForm()
return render(request, 'lala/add_new_thought.html', {
'form': form
})
In my Django project i create an app to have additional information about registered users. So my model looks like this:
class UserProfile(models.Model):
class Meta:
verbose_name_plural = u'User Profile'
user = models.OneToOneField(User)
birthday = models.DateField(blank=True, null=True)
avatar = models.ImageField(upload_to='media/profile/avatar', blank=True, null=True)
name = models.CharField(blank=True, null=True, max_length=20)
surname = models.CharField(blank=True, null=True, max_length=50)
phone = models.CharField(blank=True, null=True, max_length=12)
def __unicode__(self):
return '%s' % self.user
In user profile i create modelform where user can fill or edit the fields from UserProfile model:
class ExtraProfileDataForm(ModelForm):
name = forms.CharField(label=(u'Enter your name'))
surname = forms.CharField(label=(u'Enter your surname'))
phone = forms.CharField(label=(u'Enter your phone'))
birthday = forms.DateField(label=(u'Enter birthday'))
avatar = forms.ImageField(label=(u'Enter avatar'))
class Meta:
model = UserProfile
fields = ('name', 'surname', 'phone', 'birthday', 'avatar')
def __init__(self, *args, **kwargs):
super(ExtraProfileDataForm, self).__init__(*args, **kwargs)
for key in self.fields:
self.fields[key].required = False
This is the view of the model form:
#login_required
def UserFullDataForm(request):
if request.method == 'POST':
form = ExtraProfileDataForm(request.POST)
if form.is_valid():
profile_user = request.user
user_profile = UserProfile(user=profile_user)
user_profile.name = form.cleaned_data['name']
user_profile.surname = form.cleaned_data['surname']
user_profile.phone = form.cleaned_data['phone']
user_profile.birthday = form.cleaned_data['birthday']
user_profile.avatar = form.cleaned_data['avatar']
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/extra_profile.html', {'form':form})
else:
form = ExtraProfileDataForm()
context = {'form':form}
return render (request, 'profiles/extra_profile.html', context)
But i want to load on ExtraProfileDataForm initial data from model UserProfile if the fields not empty. I searched how to do that on Django documentation website, but nothing found. Can somebody help me to understand how to do it? Thanks a lot.
You use the instance parameter.
Note that you are doing much more work than necessary here; most of your view can be cut.
#login_required
def UserFullDataForm(request):
try:
profile = request.user.userprofile
except UserProfile.DoesNotExist:
profile = UserProfile(user=request.user)
if request.method == 'POST':
form = ExtraProfileDataForm(request.POST, instance=profile)
if form.is_valid():
form.save()
return HttpResponseRedirect('/profile/')
else:
form = ExtraProfileDataForm(instance=profile)
return render(request, 'profiles/extra_profile.html', {'form':form})
Similarly, in your form, you don't need the overridden __init__ method because you're manually specifying all the fields anyway; you can add required=False on each one there. However, you could make this even shorter by adding the labels in the model definition; then your entire modelform could just be:
class ExtraProfileDataForm(ModelForm):
class Meta:
model = UserProfile
fields = ('name', 'surname', 'phone', 'birthday', 'avatar')
One final note: you're consistently using three-space indentation, which is a bit, well, odd. Most Python programmers prefer two or four.
I want to save the database attendance data daily of each user,
but my no error no saved why? please help me
this is my full code below:
this is my views.py:
def staffs(request):
args = {}
args.update(csrf(request))
args['staffs'] = User.objects.all()
return render_to_response("staffs.html", args)
def staffdetail(request, user_id=1):
user = get_object_or_404(User, pk=user_id)
return render_to_response("staffdetail.html",
{"user": User.objects.get(id=user_id) })
def attendance(request, user_id):
if request.method == "POST":
attendance = Attendance_data(user = request.user.id)
form = AttendancekForm(request.POST, instance = attendance)
if form.is_valid():
form.save()
return HttpResponseRedirect('/articles/get/%s' % user.id)
else:
form = AttendanceForm()
return render_to_response('attendance.html', context_instance = RequestContext(request, {'form': form}))
def leave_work(request, user_id):
if request.method == "POST":
leave_work = Leave_work(user = request.user.id)
form = Leave_workForm(request.POST, instance = leave_work)
if form.is_valid():
form.save()
return HttpResponseRedirect('/articles/get/%s' % user.id)
else:
form = Leave_workForm()
return render_to_response('leave.html', context_instance = RequestContext(request, {'form': form}))
So,i'm also add my models.py and forms.py here
this is my models.py:
class User(models.Model):
user_name = models.CharField(max_length=255)
first_kana = models.CharField(max_length=255)
last_kana = models.CharField(max_length=255)
employee_number = models.CharField(blank=True, max_length=22)
created_at = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.user_name
class Attendance_data(models.Model):
user_name = models.CharField(max_length=255)
employee_number = models.CharField(blank=True)
def __unicode__(self):
return self.user_name, employee_number
class Leave_work(models.Model):
user_name = models.CharField(max_length=255)
employee_number = models.CharField(blank=True, max_length=22)
def __unicode__(self):
return self.user_name, employee_unmber
this is my forms.py:
class ArticleForm(forms.ModelForm):
class Meta:
model = User
fields = ('user_name','first_kana', 'last_kana', 'employee_number')
user_name = forms.CharField( label="name",error_messages={'required': ''})
first_kana = forms.CharField(label="firstname",error_messages={'required': ''})
last_kana = forms.CharField(label="lastname",error_messages={'required': ''})
employee_number = forms.CharField(label="number", required=False)
class Attendance_dataForm(forms.ModelForm):
class Meta:
model = Attendance_data
fields = ('user_name','employee_number')
user_name = forms.CharField(label="name", error_messages={'required': ''})
employee_number = forms.CharField(label="number",error_messages={'required': ''})
class Leave_workForm(forms.ModelForm):
class Meta:
model = Leave_work
fields = ('user_name', 'employee_number')
user_name = forms.CharField(label="name", error_messages={'required': ''})
employee_number = forms.CharField(label="number", error_messages={'required': ''})
You are doing a lot of wrong thing in your views. If you look at your model Attendence_data, it has two fields user_name and employee_number. so its constructor would accept two arguments, user_name and employee_number or any other fields that are set not to be NULL and have no default value, so passing request.user.id to the its constructor would not make it a valid object. Same is the case with Leave_work model. So if you need to do this, you need to overload the default constructor.
But seems like you are not being able to understand the basic concepts of how Django works so I'd suggest you to go trough this tutorial as this will clear a lot of basic concepts.