Django UpdateView with three different modelforms - python

I have a django UpdateView which needs to inherit three different models and different models. CreateView is working fine with three different modelforms.
models.py:
class Employee(models.Model):
"""
Create employee attributes
"""
employee_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
e_id = models.IntegerField(unique=True, null=True, blank=True)
first_name = models.CharField(max_length=128,blank=True)
last_name = models.CharField(max_length=128, blank=True)
.....
class WorkExperience(models.Model):
"""
Stores employee previous work experiences
"""
employee = models.ForeignKey('Employee', related_name='we_employee', on_delete=models.CASCADE, null=True)
previous_company_name = models.CharField(max_length=128, null=True)
job_designation = models.CharField(max_length=128, null=True)
from_date = models.DateField(null=True)
......
class Education(models.Model):
"""
Stores employee education background
"""
employee = models.ForeignKey('Employee', related_name='edu_employee', on_delete=models.CASCADE, null=True)
institution_name = models.CharField(max_length=128, null=True)
degree = models.CharField(max_length=128, null=True)
.....
views.py:
class EmployeeUpdateView(LoginRequiredMixin,UpdateView):
"""
Update a created a employee
"""
login_url = '/authentication/login/'
template_name = 'employee/employee_add_form.html'
form_class = EmployeeAddModelForm
work_form_class = WorkExperienceForm
education_form_class = EducationForm
queryset = Employee.objects.all()
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(Employee, id=id_)
WHen I go to Update view, I am only able to update EmployeeAddModelForm values. But other form's(WorkExperienceForm, EducationForm ) fields do not appear let alone edit the values of the fields.
I suppose my views.py is not correct.
I need suggestion to correct my updateview.

If you want to put multiple forms in one HTML file, in my way, write as follows.
class EmployeeUpdateView(LoginRequiredMixin,UpdateView):
login_url = '/authentication/login/'
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
def get(self, request, *args, **kwargs):
id_ = self.kwargs.get("id")
user = Employee.objects.get(id=id_)
work = WorkExperience.objects.get(employee=user)
education = Education.objects.get(employee=user)
return render(request, self.template_name, {
'form': EmployeeAddModelForm(instance=user),
'work_form': WorkExperienceForm(instance=work),
'education_form': EducationForm(instance=education)
}
)
def post(self, request):
first_name = request.POST['first_name']
# Your own code...
.....
I think the argument of each form depends on the definition of Form.
And in a very simple way, the HTML file looks like this:
<body>
<form method="post">
{% csrf_token %}
{{ employ_form }}
{{ work_form }}
{{ edu_form }}
<button type="submit">OK</button>
</form?
</body>
</html>
I'm not sure if this is the best option.

How about putting forms into get_context_data?
Something like
context['form1'] = EmployeeAddModelForm()
context['form2] = WorkExperienceForm()
Etc.
Edit:
def get_context_data(self, **kwargs):
context = super(EmployeeUpdateView, self).get_context_data(**kwargs)
context['form'] = EmployeeAddModelForm()
context['form2'] = WorkExperienceForm()
context['form3'] = EducationForm()
return context

Related

Form not being saved in Database Django

I have created a form for a Post. The form loads and when I enter all the value and try to submit the form, it gets refreshed but the database is not updated.
Here is my Post Model:
class Post(models.Model):
no_people = models.IntegerField()
no_days = models.IntegerField()
tour_date = models.CharField(max_length=200, blank=True)
Gender_types = (
('M', 'Male'),
('F', 'Female'),
('O', 'Others'),
)
Gender_prefer = models.CharField(max_length=1, choices=Gender_types)
location = models.CharField(max_length=200, blank=True)
pic_location = models.ImageField(blank=True, upload_to="posts/")
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
detail = models.TextField()
liked = models.ManyToManyField(Yatru, blank=True, related_name= 'likes')
author = models.ForeignKey(Yatru, on_delete=models.CASCADE, related_name = 'posts',null=True)
def __str__(self):
return str(self.location)
def no_likes(self):
return self.liked.all().count()
class Meta:
ordering = ('-created',)
def save(self, *args, **kwargs):
self.location = self.location.upper()
return super(Post, self).save(*args, **kwargs)
LIKE_CHOICES = (
('Like', 'Like'),
('Unlike', 'Unlike'),
)
Here is the form.py:
from django import forms
from .models import Post
class PostModelForm(forms.ModelForm):
class Meta:
model = Post
fields = ('no_people','no_days','tour_date', 'Gender_prefer','location','detail')
Here is the views.py:
def post_add(request):
user = request.user
profile = Yatru.objects.get(user=user)
form = PostModelForm(request.POST or None, request.FILES or None, instance=profile)
if request.method == 'POST':
if form.is_valid():
newpost=form.save(commit=False)
newpost.user=request.user
newpost.save()
return render(request, 'posts/my_post.html',{'form': form})
This is the HTML file:
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button type='submit'>Submit </button>
</form>
Hi please follow instructions:
First insert "author" field in field tuple of model form
In your post_add view change below line
newpost.author=request.user

Django: the detail page is not showing(template error)

am working on a Django project where showing the details of post and amount
here is my models.py of post
class Loader_post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE ,related_name="Loader")
pick_up_station = models.CharField(max_length=150)
destination_station = models.CharField(max_length=150)
sender_name = models.CharField(max_length=150)
phone_number = PhoneNumberField(null=False, blank=False, unique=True)
receiver_name = models.CharField(max_length=150)
def __str__(self):
return self.user.username
def get_absolute_url(self):
return reverse("Loader:my_job", kwargs={"pk": self.pk})
this is my second models which I inherit Loader post
class price(models.Model):
my_post = models.ForeignKey(Loader_post, related_name='prices',on_delete=models.CASCADE,
null=True, default='')
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, null=True, default='')
driver_price = models.CharField(max_length=150, null=True)
driver_name = models.CharField(max_length=150, null=True)
approved_price = models.BooleanField(default=False)
status = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse("Driver:Driverview")
def __str__(self):
return self.driver_price
this is the view.py of both list and details view
class offer_view(ListView, SelectRelatedMixin):
context_object_name = 'offern'
model = Loader_post
template_name = "offer.html"
def get_queryset(self):
qs = Loader_post.objects.filter(user=self.request.user)
return qs
class offer_view_detail(DetailView):
context_object_name = 'offernew'
model = Loader_post
template_name = "offer_detail.html"
here is my HTML page of list view ...when someone clicks on it it shows the detail of next post
offer.html
{% for my in offern %}
{{my.sender_name}} {% endfor %}
and when someone clicks on its route to the detail page .. but it shows template doesn't exist
this is my detail page ie. offer_details.hml
<p>{{offernew.sender_name}}</p>
<p>{{offernew.receiver_name}}</p>
{% for x in offernew.prices.all %}
<p>
<p>{{x.driver_name}}</p>
</p>
and this is urls.py
path('offerdetail/<int:pk>', views.offer_view_detail.as_view(),name="offerdetail"),
path('offer/', views.offer_view.as_view(), name="offer"),
Following on from comments,
In you ListView,
{{my.sender_name}}
here, the url specified is not defined in your urls.py, that's why it was showing no template doesn't exist, changing to this would solve this.
{{my.sender_name}}
Now, To show prices model in your DetailView, i would do something like this.
class offer_view_detail(DetailView):
context_object_name='offernew'
model = Loader_post
template_name = "offer_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['price_model'] = self.object.prices.all()
return context
and In your Template
<p>{{offernew.sender_name}}</p>
<p>{{offernew.receiver_name}}</p>
{% for x in offernew.price_model %}
<p>{{x.driver_name}}</p>
{% endfor %}
Django Docs for DetailView

Django user-specific variable not updating in backend

I have a set a pre-existing teams that the user can join [team1, team2, team3] at /jointeam, and that will show up on /home.
My issue is that the variable 'user_team' from Profile stays 'None', even after the user successfully joins a team.
In other words, if I enter 'team1' on /jointeam , I'd like it to assign it to user.profile.user_group
Thanks in advance, appreciate your input!
Here is my code:
Models.py
#used to create a team
class TeamCreation(models.Model):
team_name = models.CharField(max_length=100, default=None, unique=True)
[...]
def __str__(self):
return self.team_name
#user-specific
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
user_team = models.CharField(max_length=30, null=True)
[...]
def __str__(self):
return f'{self.user.username} Profile'
def save(self, *args, **kwargs):
super(Profile, self).save(*args, **kwargs)
#model to join a team
class Join(models.Model):
team_name = models.CharField(max_length=100, default=None, unique=False)
def __str__(self):
return self.team_name
Forms.py
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username','email']
class TeamCreationForm(forms.ModelForm):
class Meta:
model = TeamCreation
fields=['team_name']
class JoinForm(forms.ModelForm):
class Meta:
model = Join
fields=['team_name']
views.py - users
[...]
#login_required
def join_team(request):
form_class = JoinForm
form_join = form_class(request.POST or None)
user = request.user
if request.method=='POST':
if form_join.is_valid():
newJoin = form_join.save(commit=False)
if not TeamCreation.objects.filter(team_name=newJoin.team_name).exists():
print("nope")
return redirect('dashboard')
messages.error("Team doesn't exist or incorrect key")
else:
print("exist")
group_name=newJoin.team_name
user.profile.user_team=group_name
newJoin.save()
return redirect('dashboard')
else:
print("Error")
context={
"form":form_join,
}
return render(request, "pages/join_team.html", context)
#login_required
def home(request):
user = request.user
group_name=user.profile.user_team
context={
"user_group":group_name,
}
return render(request,'pages/dashboard.html', context)
Home.html
[...]
{% if user_team %}
<option>{{ user_team }}</option>
<option>Join a team</option>
<option>Create a team</option>
{% else %}
<option>-- none</option>
<option>Join a team</option>
<option>Create a team</option>
{% endif %}
[...]
You need to save the profile after updating it.
group_name = newJoin.team_name
newJoin.save()
user.profile.user_team = group_name
user.profile.save()
It's probably a better idea to save the profile after the join instance has been created in case it fails.

Two models in one Django DetailView and filtering by relation betwen them

I have a question. In my DetailView I want to placed data from two models. Moreover, I want to filter them, that on my scenario-detail was only that comments related to specyfic scenario, related by ForeignKey->Scenario.
My views.py:
class ScenarioDetailView(LoginRequiredMixin, DetailView):
model = Scenario
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.all()
return context
And in scenario_detail.html i have a simple {{ comments }}
I thinking on filtering my comment object in views.py, something like: Comment.objects.get(commentScenario=Scenario.id) but it didn't work at all.
My models.py:
class Scenario(models.Model):
scenarioTitle = models.CharField(max_length=256)
scenarioArea = models.ForeignKey(ScenarioArea, on_delete=models.CASCADE)
scenarioAuthor = models.ForeignKey(User, on_delete=models.CASCADE)
scenarioDate = models.DateTimeField(default=timezone.now)
scenarioDescription = models.TextField()
def __str__(self):
return self.scenarioTitle
def get_absolute_url(self):
return reverse('scenario-detail', kwargs={'pk': self.pk})
class Comment(models.Model):
commentText = models.CharField(max_length=256)
commentScenario = models.ForeignKey(Scenario, on_delete=models.CASCADE)
commentAuthor = models.ForeignKey(User, on_delete=models.CASCADE)
commentDate = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.commentText
And urls.py:
path('scenario/<int:pk>/', ScenarioDetailView.as_view(), name='scenario-detail'),
Could someone help me?
You don't need to send any extra context to your template in order to show the related comments; As you already have the related comments to your Scenario with backward relationship.
So you can simply use Scenario.comment_set.all in your template to access them.
As an example:
{% for comment in object.comment_set.all %}
{{ comment }}
{% endfor %}
try this
class ScenarioDetailView(LoginRequiredMixin, DetailView):
model = Scenario
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.filter(commentScenario=self.object)
return context

How to display records belongs only for user instead for all users

I have a little problem. I want to to display in list only records belongs to user whos add it. In my app when I'am login as 'user' and I want to add new records incude records from list, I see all records in db from ForeignKey. How to make it correctly?
In 'Strona www' when I expand the list I see all records, not only records added by user personally.
My view for it is:
#login_required
def new_keyword(request):
if request.method == "POST":
new_keyword = KeywordForm(request.POST)
if new_keyword.is_valid():
new_keyword=new_keyword.save(commit=False)
new_keyword.user = request.user
new_keyword.save()
messages.success(request, 'Pomyślnie dodano słowo kluczowe')
return render(request, 'konto/new_keyword_ok.html')
else:
new_keyword = WebsiteForm()
return render(request, 'konto/new_keyword.html', {'new_keyword':new_keyword})
in forms.py I have:
class KeywordForm(forms.ModelForm):
class Meta:
model = Keyword
fields = ('www', 'keyword')
models.py
class Keyword(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Użytkownik")
www = models.ForeignKey(Website, on_delete=models.CASCADE, verbose_name="Strona www")
keyword = models.CharField(max_length=250, verbose_name="Słowo kluczowe", unique=False)
urls.py
path('new-keyword/', new_keyword, name='new_keyword'),
and html for display the form is:
{% if request.user.is_authenticated %}
<form action="." method="post">
{{ new_keyword.as_p }}
{% csrf_token %}
<p><input type="submit" value="Dodaj nowe słowo kluczowe" ></p>
Powrót do monitoringu
</form>
{% endif %}
EDIT:
models.py
from django.db import models
from django.contrib.auth.models import User
class Website(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Użytkownik")
website = models.CharField(max_length=250,verbose_name='Strona www', unique=False)
class Meta:
verbose_name = 'Strona www'
verbose_name_plural = 'Strony www'
def __str__(self):
return self.website
class Keyword(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Użytkownik")
www = models.ForeignKey(Website, on_delete=models.CASCADE, verbose_name="Strona www")
keyword = models.CharField(max_length=250, verbose_name="Słowo kluczowe", unique=False)
class Meta:
verbose_name = 'Słowo kluczowe'
verbose_name_plural = 'Słowa kluczowe'
def __str__(self):
return self.keyword
Pass the request.user to your form and use the inverse relation user.website_set :
forms :
class KeywordForm(forms.ModelForm):
class Meta:
model = Keyword
fields = ('www', 'keyword')
def __init__(self, user, *args, **kwargs):
super(KeywordForm, self).__init__(*args, **kwargs)
self.fields['www'].queryset = user.website_set.all()
self.user = user
def save(self, commit=True):
instance = super(KeywordForm, self).save(commit=False)
instance.user = self.user
if commit:
instance.save()
return instance
views:
#login_required
def new_keyword(request):
if request.method == "POST":
new_keyword = KeywordForm(request.user, request.POST)
if new_keyword.is_valid():
new_keyword.save()
messages.success(request, 'Pomyślnie dodano słowo kluczowe')
# DONT DO THIS ! REDIRECT INSTEAD
return render(request, 'konto/new_keyword_ok.html')
else:
new_keyword = KeywordForm(request.user)
return render(request, 'konto/new_keyword.html', {'new_keyword':new_keyword})
As a side note: after a successful POST you want to redirect (even if to the same url). This avoids a lot of troubles (and duplicate submissions) when a user reloads the page
Just pass the user id to your form and then set a queryset for your field
like this:
How to pass the user to your form:
in your view:
#login_required
def new_keyword(request):
if request.method == "POST":
#### Notice this part.
new_keyword = KeywordForm(data=request.POST, u=request.user)
if new_keyword.is_valid():
new_keyword=new_keyword.save(commit=False)
new_keyword.user = request.user
new_keyword.save()
messages.success(request, 'Pomyślnie dodano słowo kluczowe')
return render(request, 'konto/new_keyword_ok.html')
else:
# Notice this part.
new_keyword = WebsiteForm(data=None, u=request.user)
return render(request, 'konto/new_keyword.html', {'new_keyword':new_keyword})
How to retrieve the user in form and set the queryset:
forms.py:
class KeywordForm(forms.ModelForm):
class Meta:
model = Keyword
fields = ('www', 'keyword')
def __init__(self, current_user, *args, **kwargs):
self.u = kwargs.pop("u") ## The user you just passed.
super(KeywordForm, self).__init__(*args, **kwargs)
self.fields['www'].queryset = Website.objects.filter(user=self.u) ## Setting the queryset.

Categories

Resources