Django save ManyToManyField Model with ModelMultipleChoiceField - python

So I know there are a few similar questions but none of the solutions worked for me. I've tried save(commit=false) and save_m2m as well as a bunch of other stuff but i get the error
NOT NULL constraint failed: home_services.managers_id
Anyways here's my code:
views.py
def service(request):
if request.user.is_authenticated:
if request.method == 'POST': #Create Service
form = CreateServiceForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/service') #Later change this to redirect to server page
else:
form = CreateServiceForm()
args = {'user': request.user, 'form': form}
return render(request, 'service.html', args)
else:
return HttpResponseRedirect('/feed')
models.py
class Services(models.Model):
name = models.CharField(max_length=100, default='')
description = models.CharField(max_length=500, default='')
owner = models.OneToOneField(User, on_delete=models.CASCADE)
managers = models.ForeignKey(User, related_name="managers", on_delete=models.CASCADE)
members = models.ManyToManyField(User, related_name="members")
def __str__(self):
return str(self.name) + ": id" + str(self.id)
forms.py
class CreateServiceForm(forms.ModelForm):
owner = forms.ModelChoiceField(queryset=User.objects.all())
members = forms.ModelMultipleChoiceField(queryset=User.objects.all())
class Meta:
model = Services
fields = [
'name',
'description',
'owner',
'members',
]
I want the user to be able to create a service and select 1 or more members that is in the default django User model.

I want the user to be able to create a service and select 1 or more members that is in the default django User model.
You are not providing managers, which is not allowed as per the current configuration.
So, change:
managers = models.ForeignKey(
User,
related_name="managers",
on_delete=models.CASCADE,
)
To:
managers = models.ForeignKey(
User,
related_name="managers",
on_delete=models.CASCADE,
blank=True,
null=True,
)
You might want to read more about blank and null.

Related

How to use default field values for ForeignKey?

I'm just starting to learn Django and building a simple blog with it.
So i have two models Post and PostStatistics. When ever i add a new post, i want that PostStatistics contains all specified default values. How can i achieve this correctly?
models.py
class PostStatistics(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4)
post_views = models.IntegerField(default=0)
post_likes = models.IntegerField(default=0)
post_favorites = models.IntegerField(default=0)
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4)
user = models.ForeignKey(UserProfile, null=True, on_delete=models.CASCADE)
statistics = models.ForeignKey(PostStatistics, null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
body = RichTextField(blank=True, null=True)
draft = models.BooleanField(default=False)
views.py
def add_post(request: HttpRequest):
form = PostForm(request.POST)
is_draft = True if form.data.get("draft") == "on" else False
post = Post(
title=form.data["title"],
body=form.data["post"],
user=request.user,
draft=is_draft,
statistics = PostStatistics() -> this is not correct
)
post.save()
return redirect("post")
At the moment i get FOREIGN KEY constraint failed.
You create a new one:
def add_post(request: HttpRequest):
form = PostForm(request.POST)
is_draft = form.data.get('draft') == 'on'
post_statistics = PostStatistics.objects.create()
Post.objects.create(
title=form.data['title'],
body=form.data['post'],
user=request.user,
draft=is_draft,
statistics = post_statistics
)
return redirect('post')
It however does not make much sense to store the statistics in a separate model, since there is a clear one-to-one relation, and thus the statistics can be stored in the Post model.
Furthermore you can use the form to validate the input and also create the object (or at least parts of it). A better modeling thus might be:
from django.conf import settings
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4)
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE, editable=False)
title = models.CharField(max_length=200)
body = RichTextField(blank=True, null=True)
draft = models.BooleanField(default=False)
post_views = models.IntegerField(default=0, editable=False)
post_likes = models.IntegerField(default=0, editable=False)
post_favorites = models.IntegerField(default=0, editable=False)
and then work with a ModelForm where you let the form do all the proper validation and cleaning:
from django.contrib.auth.decorators import login_required
#login_required
def add_post(request: HttpRequest):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('post')
else:
form = PostForm()
return render(request, 'name-of-some-template.html', {'form': form})
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

how do I request a user and save the user in a Foreignkey field of a model

When I do this exactly as provided below, a shipping address object is created without the customer assigned in the shipping address foreignkey field, I can add it from the admin panel manually but I'm not able to make it work through code
**models.py**
class Customer(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, blank=True, null=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(max_length=150)
class ShippingAddress(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
address_one = models.CharField(max_length=200)
address_two = models.CharField(max_length=200)
...
**views.py**
def checkout(request):
if request.method == 'POST':
form = ShippingForm(request.POST)
customer = request.user.customer
if form.is_valid():
# how to add the customer object to the foreignkey field of the shipping address
form.save()
return redirect('store:checkout_shipping')
else:
form = ShippingForm()
else:
form = ShippingForm()
context = {"form": form}
return render(request, 'store/checkout.html', context)
ShippingAddress.objects.get(customer=customer)
This returns a ShippingAddress, but
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, blank=True, null=True)
requires a CustomUser. These are incompatible, so you cannot assign them.
But you are already getting the user:
customer = request.user.customer
Just reduce this a little:
user = request.user
now you have a user object.
I am assuming that you have correctly set up the CustomUser class in the Django settings.

Django: NOT NULL constraint failed: account_tutorvalidator.user_id

I am new to django and I created this "apply now form" exclusively for tutors that when they submit the form it will appear to the admin site, and I will manually check it if they are a valid tutor. And if they are a valid tutor, I will check the is_validated booleanfield in the admin site to the corresponding tutor that sent the form, so that he/she will have access to other things in the site. But I am having this problem that when you submit the form this comes up..
NOT NULL constraint failed: account_tutorvalidator.user_id
I have search for some solutions and also read similar questions here but I still couldn't understand what to do.. could someone help me out with this?
here is my models.py
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_tutor = models.BooleanField(default=False)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
phone_number = models.CharField(max_length=11, blank=False, null=True)
current_address = models.CharField(max_length=100, null=True)
image = models.ImageField(default='default-pic.jpg', upload_to='profile_pics')
def __str__(self):
return f'{self.first_name} {self.last_name}'
class TutorProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True,
related_name='tutor_profile')
bio = models.CharField(max_length=255, blank=True)
is_validated = models.BooleanField(default=False)
def __str__(self):
return f"{self.user.first_name} {self.user.last_name}'s Profile"
class TutorValidator(models.Model):
user = models.ForeignKey(TutorProfile, on_delete=models.CASCADE)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
dbs = models.ImageField(upload_to='dbs_pics')
driving_license = models.ImageField(upload_to='drivers_license_pics', null=True, blank=True)
national_id = models.ImageField(upload_to='national_id_pics', null=True, blank=True)
def __str__(self):
return f"{self.first_name}'s application form"
my forms.py
class TutorValidationForm(forms.ModelForm):
class Meta:
model = TutorValidator
fields = ['first_name', 'last_name', 'driving_license', 'national_id']
labels = {
'national_id': _('National ID')
}
my views.py
class TutorValidatorView(LoginRequiredMixin, FormView):
template_name = 'account/tutor_validator.html'
form_class = TutorValidationForm
success_url = '/'
The error is because TutorValidator requires that you set the user profile foreign key which your form currently does not support, so you need a way to set this to the object you are creating, and use the current logged in user (the one who is submitting the form).
You can do this by overriding form_valid. Try with:
class TutorValidatorView(LoginRequiredMixin, FormView):
...
def form_valid(self, form):
tutor_validator = form.save(commit=False)
tutor_validator.user = self.request.user.tutor_profile
tutor_validator.save()
return HttpResponseRedirect(self.get_success_url())
Note that the current user needs to already have an existing TutorProfile. Otherwise you need to create that first to connect it to TutorValidator

Django Foreign key field validation in a forms or models ( getting info created by only that user from foreign key)

I'm trying to build courses and add lessons to a course later and the problem I encounter is that every user can choose to add courses to another person created courses.
Like if you create some courses, another user will see as an option to add his lesson to it
views.py
def creatingLessonsForm(request):
form = CreatingLessonsForm(request.POST or None)
if form.is_valid():
post = form.save(commit=False)
post.CreatedBy = request.user
post.save()
form = CreatingLessonsForm()
context = {'form': form}
return render(request, 'courses/creatingLessonsForm.html', context)
models.py
class CreatingCourses(models.Model):
NameOfTheCourses = models.CharField("Name of the courses", max_length=60, blank=False)
Category = models.ForeignKey(Subject, on_delete=models.CASCADE)
CreatedBy = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
Document = models.ForeignKey(Document, on_delete=models.SET_NULL, verbose_name= "Select document for courses introduction", blank=True , null=True)
IncludeTest = models.ForeignKey(GenaratedTest, on_delete=models.SET_NULL, verbose_name= "Include test for courses", blank=True , null=True)
AdditionalInfo = models.TextField("Additional info for courses introduction", max_length=300, blank=False)
Note = models.TextField("Notes", max_length=180, blank=True)
Show_the_courses = models.BooleanField(verbose_name= "Show the courses for everyone?",default=True)
def __str__(self):
return str(self.NameOfTheCourses) if self.NameOfTheCourses else ''
class CreatingLessons(models.Model):
Courses = models.ForeignKey(CreatingCourses, on_delete=models.SET_NULL, null=True)
NameOfTheLesson = models.CharField(max_length=60, verbose_name= "Name of the lesson", blank=False)
Document = models.ForeignKey(Document, on_delete=models.SET_NULL, verbose_name= "Document for lesson", blank=True , null=True)
CreatedBy = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
Lesson = models.TextField(max_length=250, verbose_name= "Lesson", blank=False)
Note = models.TextField("Notes", max_length=100, blank=True)
Show_the_lesson = models.BooleanField(verbose_name= "Show the lesson inside courses?",default=True)
forms.py
class CreatingCoursesForm(forms.ModelForm):
class Meta:
model = CreatingCourses
fields = ['NameOfTheCourses', 'Category', 'IncludeTest', 'Document' , 'AdditionalInfo', 'Note', 'Show_the_courses' ]
class CreatingLessonsForm(forms.ModelForm):
class Meta:
model = CreatingLessons
fields = ['Courses', 'NameOfTheLesson', 'Document', 'Lesson', 'Note', 'Show_the_lesson']
Image of webpage:
You need to pass the user when you initialize the form and then filter the queryset for the available courses that can be selected
class CreatingLessonsForm(forms.ModelForm):
def __init__(self, data=None, user=None, **kwargs):
super().__init__(data, **kwargs)
self.fields['Courses'].queryset = CreatingCourses.objects.filter(CreatedBy=user)
And then when you initialize the form pass the user
# When rendering the initial form
form = CreatingLessonsForm(user=request.user)
# When passing POST data to the form
form = CreatingLessonsForm(request.POST, user=request.user)
One option would be to modify your to filter the courses by user.
class CreatingLessonsForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
request_user = kwargs.pop('request_user')
super().__init__(*args, **kwargs)
self.fields['Courses'].queryset = self.fields['Courses'].queryset.filter(
CreatedBy=request_user)
For that to work you will need to pass in the user of the request to the form, maybe like this:
def creatingLessonsForm(request):
data = request.POST.copy()
data['request_user'] = request.user
form = CreatingLessonsForm(data)
...

UNIQUE constraint failed username error while changing user details

I have custom user model by extending AbstractUser class. I want to make form to change user's fullname and website field.
My user:
class Hacker(AbstractUser):
name = models.CharField(max_length=255)
team = models.ForeignKey(Team, on_delete=models.CASCADE, blank=True, null=True)
description = models.CharField(max_length=255, blank=True, null=True)
website = models.URLField(max_length=200, blank=True, null=True)
def __str__(self):
if self.name:
return self.name
else:
return self.username
And forms.py:
class ProfileForm(forms.ModelForm):
"""
Edit profile form
"""
name = forms.CharField(label=_("Name"),
widget=forms.TextInput(attrs={'placeholder': _('Name')}))
description = forms.CharField(label=_("Description,Position"), required=False,
widget=forms.TextInput(attrs={'placeholder': _('Description, Position')}))
website = forms.URLField(label=_("Website"), required=False,
widget=forms.TextInput(attrs={'placeholder': _('Website URL')}))
class Meta:
model = get_user_model()
fields = ['name', 'description', 'website']
In page I use {{ field }} to add inputs and in POST part of views:
form = ProfileForm(request.POST)
if form.is_valid():
form.save(commit=True)
...
But form.save gives UNIQUE constraint failed: common_hacker.username error. What can be problem here?
Adding instance=request.user when creating form fixed problem:
form = ProfileForm(request.POST, instance=request.user)

Categories