How to save choices value in django ? - python

I am donig with a poll system for my class. I use model-form and create-view to serve the poll form. I use choices in in the field but I just find out that create-view only save the last value of the checkboxes and I want to save all the selected choices as a list maybe. I've tried to change the form_valid() method, but I just find out that I need to iterate all the fields to check wheather there are multipule choices. It's not flexible. And I can't figure out other solutions...
How can I meet this requirement? I am truly a newbie..
Thanks in advance.
Thank the friend below for replying in such a short interval after I raised my question. Here is my code.
models.py
CHOICES = (('m','Math'),('f','French'),('s','Science'),('l','literature'))
class Poll(models.Model):
[...]
subject = models.CharField(max_length = 5,choices = CHOICES, blank=True)
[...]`
forms.py
class PollForm(forms.ModelForm):
model = Poll
fields = [..., 'subject', ...]
widgets = {'subject':forms.CheckboxSelectMultiple}
views.py
class PollView(CreateView):
form_class = PollForm
template_name = 'poll.html'
Students can choose subjects they want.

It seems like you need to convert your model. If you could provide a sample of the structure that you are using it would be helpful. Still lets try solving your query. First you need identify that choices is nothing more than a many to many field. Saving it in the db should be a bit easier that way. Lets try taking an example with choices for a user:
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 if you want to make a default form you could simply do something like:
class ProfileForm(forms.ModelForm):
Meta:
model = UserProfile
Now comes your main view. This can be editted and rendered to whatever your use case demands it to be:
if request.method=='POST':
form = ProfileForm(request.POST)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
#Implement this as a pre-save so that you can add additional value
profile.save()
else:
form = ProfileForm()
Hope this helps.

Related

Django Model: How to only access fields related to a specific user from another model

How can i only access the addresses(Address model) of specified user(User model) from Order model.
here is the code: Models.py
class User(AbstractBaseUser, PermissionsMixin):
phone_number = PhoneField(max_length=12, primary_key=True, unique=True)
class Address(models.Model):
address = models.CharField(max_length=500, blank=False,null=False,primary_key=True)
customer = models.ForeignKey((User, on_delete= models.CASCADE)
class Order(models.Model):
order = CharField(max_length=400,blank=False,null=False)
customer = models.ForeignKey(User,on_delete=models.SET_NULL, null=True)
address = models.ForeignKey(Address,on_delete=models.SET_NULL, null=True)
the address field in Order model is my problem. When creating a new order in Django Administration, when i select one of the customers, i still can choose any address registered in database
How can i limit the access to addresses to specified user.
Thanks in advance
You can not filter this in the models. You will need to do that by the form layer.
We can implement this with:
class MyForm(forms.ModelForm):
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
self.fields['address'].queryset = Address.objects.filter(user=user)
class Meta:
model = Order
fields = ['address']
then in the view, we can construct a form with the logged in user as user:
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
if request.method == 'POST':
form = MyForm(request.POST, user=request.user)
if form.is_valid():
form.instance.user = request.user
# set the order number to the instance
form.save()
return redirect('name-of-some-view')
else:
form = MyForm(user=request.user)
return render(request, 'name-of-some-template.html', {'form': form})
It depends if customers should be allowed to have multiple addresses (like in most online shops). In that case the User and Address models look pretty good!
Django Admin can be a bit tricky. But that's just the nature of the flow, because the moment you open the "Create Order Page" the server has no idea what user you will pick, and therefore does not know which address it should filter. You would have to use ajax to get to your goal, but I can propose something different...
The question is why did you add another address field to the Order? Don't get me wrong, it's the right way actually. But...
What if the user orders something, changes his address object and looks back at the order history?
Actually you COULD drop the address-foreignkey on the order and you'll still be able to access the current customer address on any order, by:
some_order = Order.objects.first()
customer = some_order.customer
# As defined in your model, one customer can have many addresses. For now just access the "latest" one
customers_address = customer.address_set.last()
But the order history would still be messy... now its even worse. Whenever the customer adds or changes the address, the order history would show wrong values.
To prevent this, you could leave the foreign key, prevent the address_id from being edited (read_only field), prevent the related address object from being edited, and add a flag if the address is visible to the user or soft-deleted.
You should do some research about read_only fields, editable and overriding model methods
But to keep things a bit more simple, lets just change the Order->address field to be a Charfield instead of a foreign key. You won't need to show an editable field inside the admin anymore and instead let the user have his default address.
class Order(models.Model):
order = CharField(max_length=400,blank=False,null=False)
customer = models.ForeignKey(User,on_delete=models.SET_NULL, null=True)
shipping_address = models.CharField(max_length=500, editable=False)
def save(self, *args, **kwargs):
# You can use this field to stringify even more complex objects
# Again, last() is not the right way in the end but you could have a specific field on the customer: preferred_address
self.shipping_address = self.customer.address_set.last().address
super().save(*args, **kwargs)

How to access User Profile's friends in ManyToMany field

I am building a simple social media app. AND i am trying to build a feature of adding users into post using ManyToManyField.
I am trying to access profile friends in Post's model instance "add_user" for tagging user.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,default='',unique=True)
full_name = models.CharField(max_length=100,default='')
friends = models.ManyToManyField("Profile",blank=True)
class Post(models.Model):
post_owner = models.ForeignKey(User,default='',null=True,on_delete = models.CASCADE)
post_title = models.CharField(max_length=500,default='')
add_user = models.ManyToManyField(User.profile.friends.all())
I am new in django and I have no idea how can i access user's friend in Post's model instance.
Any help would be much Appreciated.
Thank You in Advance.
You can't give a queryset as an argument for a ManyToManyField, just a class name.
add_users = models.ManyToManyField(User.profile.friends.all()) # you can't do this.
add_users = models.ManyToManyField(User) # Do this.
You shouldn't place you logic in your model's definition.
Do that in your views.
EDIT:
I suggest you use a ModelChoiceField and do the filtering logic there:
class AddFriendForm(forms.Form):
def __init__(self, *args, **kwargs):
try:
user = kwargs.pop('user')
except:
user = None
super(AddFriendForm, self).__init__(*args, **kwargs)
self.fields['friend'].queryset = user.profile.friends.all()
friend = forms.ModelChoiceField(queryset=User.objects.none())
And then in your view you initialize it like this:
def your_view(request):
form = AddFriendForm(user=request.user)
You cannot do
add_users = models.ManyToManyField(User.profile.friends.all())`
Because the models is evaluated once, and need to be non mutable values
You need to do :
add_user = models.ManyToManyField("Profile",blank=True)
And dont forget to add on your ManyToManyField:
related_name="XXX", null=True

How to save two related entries in a single form

I am new to Django and I am creating a simple 2 page messageboard app (submit page and messageboard page)
I am struggling with the form for my submit page. As I am learning my way around Django I decided not to use the standard user model and opted to rather create a model (Poster) which has a one to one relationship with the message model.
Basically in one form I would like to add a message and a poster(foreign key) which has multiple fields.
Is it possible to achieve what I am trying to do?
Thanks in advance for the help.
I don't really know what to try or what to look for. I have included some code below.
Models
class Poster(models.Model):
full_name = models.CharField(max_length = 50)
phone_number = models.CharField(max_length = 15)
email = models.EmailField()
class Message(models.Model):
message_text = models.CharField(max_length=10000)
created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(Poster, on_delete=models.CASCADE)
class MessageForm(forms.ModelForm):
class Meta:
model = Message
fields = ['full_name', 'phone_number', 'email', 'message_text']
Your mistake is trying to use a ModelForm subclass which is for creating or updating one object (database row) only.
Use a plain forms.Form with the fields you want. You'll have to explicitly code them as CharField, EMailField, etc. Then in form_valid (assuming your view is a FormView) you will do something like
poster = Poster()
poster.full_name = form.cleaned_data['full_name']
# ditto for phone_number and email
poster.save()
message = Message( user=poster,
message_text = form.cleaned_data['message_text'] )
message.save()

Differentiate between 'account types' in Django

Thanks in advance if you're reading this... I'm a High School student working on a web application using Django, to help students find internships, and facilitate parents posting internship offers -- a sort of marketplace if you will.
I'm trying to create a profile/account page for the users but I need a way to differentiate between whether the account logged in is a Student or Employer so that I can use views.py to generate a page appropriate to their account.
In models.py, I have two different profile types which can be associated with a user account (handled by django.contrib.auth), see below for reference.
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profilePic = models.ImageField(default='default.jpg', upload_to='profile_pics')
class Meta:
verbose_name = 'Student Profile'
def __str__(self):
return f"{self.user.username}'s Profile"
class Employer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profilePic = models.ImageField(default='default.jpg', upload_to='profile_pics')
company = models.CharField(max_length=100, default='Unspecified')
class Meta:
verbose_name = 'Employer/Parent Profile'
def __str__(self):
return f"{self.user.username}'s Profile"
In my views.py page, I'm trying to create a view for the account/profile that can detect whether the currently logged-in user's profile is linked to either the 'Student' or 'Parent' model and serve a page accordingly. I've tried a very rudimentary approach, as below, but unsurprisingly it's not working.
def account(request):
if user.student.username == True:
context = 'Account: Student'
return render(request, 'users/studentprofile.html', context)
elif user.employer.username == True:
context = 'Account: Employer'
return render(request, 'users/employer.html', context)
I was wondering if anyone had a suggestion as to how I can best accomplish this... apologies in advance is this approach is poorly structured or against the status-quo of Django Programming, I'm a complete beginner!
Thanks in advance all :)
As Morteza Afshari said, you should reorganize your models to include a boolean field.
class CustomUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profilePic = models.ImageField(default='default.jpg', upload_to='profile_pics')
is_student = models.BooleanField(default=True)
class Meta:
verbose_name = 'Profile'
def __str__(self):
return f"{self.user.username}'s Profile"
This follows the DRY principle much better than your prior code because now we're not repeating fields like user, profilePic, etc.
Now we can rewrite your views.py like this:
def account(request):
if user.is_student:
context = 'Account: Student'
return render(request, 'users/studentprofile.html', context)
else:
context = 'Account: Employer'
return render(request, 'users/employer.html', context)
it would be better if you posted your exception/error alongside your code
but here's some hint:
context parameter passed to render function should be a dictionary not an string
context = {'Account: Student'}
and you should access to user with request.user not just user
if problems above didn't solve your problem
add these two lines of code at the beginning of your function:
print(request.user.student)
print(request.user.employer)
You can have an boolean field in user model like is_student and fill it during sign in. It can be null=True and null when user signed out.
If you have jwt token, you can store additional data in token to check where it comes from, or either store user current role in its cookie. Get us more data about your site structure for more related answers. (Data about authentication system, database structure or any more structural behaviors)

Saving Form Data with a ForeignKey Field

I want to expand my User Model with a UserProfile model. This UserProfile model includes a ForeignKey Field. In the form, I would like to use a ModelChoiceField to pre-populate this form field.
Whenever I submit the form, I get
ValueError at /accounts/register/
Cannot assign "'13'": "UserProfile.course" must be a "Course" instance.
Any help would be appreciated!
My Code:
models.py
class Course(models.Model):
course_accid = models.CharField(max_length=10)
def __str__(self):
return self.course_accid
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
website = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_images', blank=True)
course = models.ForeignKey(Course)
def __unicode__(self):
return self.user.username
def user_registered_callback(sender, user, request, **kwargs):
profile = UserProfile(user = user)
profile.website = request.POST["website"]
profile.course = Course.objects.get(pk=request.POST["course"]),
profile.save()
forms.py
class RegistrationForm(RegistrationForm):
course = forms.ModelChoiceField(queryset=Course.objects.all())
website = forms.URLField()
So, the problem that's occurring is that course needs to be set to a course instance with a step before, on forms.py, before it's a ModelChoiceField. The reason why is because querying it, like you're doing with queryset is really just searching for a string that matches, not the actual object.
If you break it up into two steps,
class = [some_method_for_getting_a_class_object]
UserProfile.class = class
Then it should get rid of that error.

Categories