Django Creating a new post, but it belongs to none - python

Creating a new checklist, the checklist get created but I have to go inn admin panel to set what task it belongs to. The task is a foreignkey in the checklist.
views.py
def project_detail(request, slug):
'''
Detailed view of given project
'''
context = {}
project = get_object_or_404(Project, slug=slug)
tasks = Task.objects.filter(task_completed=False, project=project)
context.update({'project': project})
checklist_form = ChecklistForm(request.POST or None)
if request.method == "POST":
# Create new Checklist
if 'save_new_checklist' in request.POST:
if checklist_form.is_valid():
print("\n\n New checklist form is valid")
author = Profile.objects.get(user=request.user)
new_checklist = checklist_form.save(commit=False)
new_checklist.user = author
new_checklist.tasks = tasks
new_checklist.save()
return redirect('project_detail', slug=slug)
context.update({
'tasks': tasks,
'checklist_form': checklist_form,
'title': tasks
})
return render(request, 'projects/tasks.html', context)
models.py
class Task(models.Model):
title = models.CharField(max_length=55, null=True, blank=True)
slug = models.SlugField(max_length=500, unique=True, blank=True)
task_completed = models.BooleanField(default=False)
description = models.TextField(default="Task description")
date = models.DateTimeField(auto_now_add=True)
due_date = models.DateTimeField()
project = models.ForeignKey(Project, blank=True, null=True, related_name='task', on_delete=CASCADE)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Task, self).save(*args, **kwargs)
def __str__(self):
return self.title
class Checklist(models.Model):
title = models.CharField(max_length=55)
slug = models.SlugField(max_length=500, unique=True, blank=True)
date = models.DateTimeField(auto_now_add=True)
due_date = models.DateTimeField()
check_completed = models.BooleanField(default=False)
description = models.TextField(default="Checklist description")
task = models.ForeignKey(Task, blank=True, null=True, related_name='checklist', on_delete=CASCADE)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Checklist, self).save(*args, **kwargs)
def get_url(self):
return reverse('task_detail', kwargs={
'slug':self.slug
})
def __str__(self):
return self.title
urls.py
urlpatterns = [
path('projects/', teams, name='teams'),
path('projects/project/<slug>/', projects, name='projects'),
path('projects/tasks/<slug>/', project_detail, name='project_detail'),
path('projects/checklist/<slug>/', task_detail, name='task_detail'),
]
The form is valid, no errors, the new checklist is created, only that it should be automatically belong to the given task. And it does not, have to go admin panel and choose what task it belongs to.

Related

Setup UpdateView in Django with a form that has the __init__ method configured

When I use UpdateView in Django with a form that has the __init__ method configured to customize the ModelMultipleChoiceField querysets do not load the initial values of the instance?
Some context first, I find myself making an application that manages documents associated to subportals, for that each subportal has associated Service Groups and Dependencies.
I need that when a document is loaded, it can be categorized by Service Groups and Dependencies that are only associated to the subportal. I achieved this by using the __init__ method in the forms.
The problem is that when I need to update the document data, the initial values of the model do not appear.
I show the codes
Models.py
class ServiceGroup(models.Model):
subportal = models.ForeignKey(Subportal, null=True, blank=True, on_delete=models.CASCADE)
title = models.CharField(max_length=150, null=False, blank=False)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Dependence(models.Model):
subportal = models.ForeignKey(Subportal, null=True, blank=True, on_delete=models.CASCADE)
title = models.CharField(max_length=150, null=False, blank=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class SubportalDocument(models.Model):
def get_upload_to(instance, filename):
return '{}/documents/{}'.format(instance.subportal.title, filename)
subportal = models.ForeignKey(Subportal, null=True, blank=True, on_delete=models.CASCADE)
showcategory = models.OneToOneField(ShowCategory, null=True, blank=True, on_delete=models.CASCADE)
title = models.CharField(max_length=150, null=False, blank=False)
file = models.FileField(upload_to=get_upload_to, null=False, blank=False)
review_date = models.DateField(null=False, blank=True)
review_nro = models.IntegerField(null=False, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
dependences = models.ManyToManyField(Dependence, related_name='dependencesdoc', blank=True)
servicegroups = models.ManyToManyField(ServiceGroup, related_name='servicegroupsdoc', blank=True)
def __str__(self):
return self.title
Forms.py
class SubportalDocumentForm(forms.ModelForm):
class Meta:
model = SubportalDocument
exclude = ['subportal', 'created_at', 'status']
labels = {
'showcategory':'Categoría de Despliegue:',
'title':'Nombre del Documento:',
'file':'Cargar el archivo:',
'review_nro':'Número de Revisión:',
'review_date':'Fecha de Revisión:',
}
widgets = {
'showcategory':forms.Select(attrs={'class':'form-select'}),
'title':forms.TextInput(attrs={'class':'form-control'}),
'file':forms.FileInput(attrs={'class':'form-control'}),
'review_nro': forms.NumberInput(attrs={'class':'form-control'}),
'review_date': forms.DateInput(format=('%d/%m/%Y'),
attrs={'class':'form-control',
'type':'date'}),
}
servicegroups = forms.ModelMultipleChoiceField(
label='Grupos de Servicios:',
queryset=None,
widget=forms.CheckboxSelectMultiple,
)
dependences = forms.ModelMultipleChoiceField(
label='Dependencias:',
queryset=None,
widget=forms.CheckboxSelectMultiple,
)
def __init__(self, *args, **kwargs):
self.subportal = kwargs.pop('subportal')
super(SubportalDocumentForm, self).__init__(*args, **kwargs)
self.fields['servicegroups'].queryset = ServiceGroup.objects.filter(
subportal=self.subportal)
self.fields['dependences'].queryset = Dependence.objects.filter(
subportal=self.subportal)
self.fields['showcategory'].queryset = ShowCategory.objects.filter(
subportal=self.subportal)
self.fields['servicegroups'].widget.attrs.update({
'class': 'form-check-input',
})
self.fields['dependences'].widget.attrs.update({
'class': 'form-check-input',
})
Views.py
class SubportalDocumentUpdateView(UpdateView):
model = SubportalDocument
form_class = SubportalDocumentForm
template_name = 'portal_manager/create_document.html'
def get_form_kwargs(self, *args, **kwargs):
subportal_id = self.get_object().subportal_id
subportal = get_object_or_404(Subportal, id=subportal_id)
kwargs = {
"subportal": subportal,
}
return kwargs
def dispatch(self, request, *args, **kwargs):
id = self.get_object().subportal_id
self.get_form().fields['servicegroups'].queryset = ServiceGroup.objects.filter(subportal_id=id)
self.get_form().fields['dependences'].queryset = Dependence.objects.filter(subportal_id=id)
return super(SubportalDocumentUpdateView, self).dispatch(request, *args, **kwargs)
def get_success_url(self):
id = self.get_object().subportal_id
return reverse_lazy('portal_manager:admin_subportal', kwargs={'id': id})
Urls.py
path('modificar-documento/<int:pk>', views.SubportalDocumentUpdateView.as_view(), name='update_document'),
The result I get is this.
image of the form without the initial values:
Now, if I don't use the __init__ method in the forms to filter the Service Groups and Dependencies by subportal, I get the initial values.
forms.py not init
class SubportalDocumentForm(forms.ModelForm):
class Meta:
model = SubportalDocument
exclude = ['subportal', 'created_at', 'status']
labels = {
'showcategory':'Categoría de Despliegue:',
'title':'Nombre del Documento:',
'file':'Cargar el archivo:',
'review_nro':'Número de Revisión:',
'review_date':'Fecha de Revisión:',
}
widgets = {
'showcategory':forms.Select(attrs={'class':'form-select'}),
'title':forms.TextInput(attrs={'class':'form-control'}),
'file':forms.FileInput(attrs={'class':'form-control'}),
'review_nro': forms.NumberInput(attrs={'class':'form-control'}),
'review_date': forms.DateInput(format=('%d/%m/%Y'),
attrs={'class':'form-control',
'type':'date'}),
}
servicegroups = forms.ModelMultipleChoiceField(
label='Grupos de Servicios:',
queryset=ServiceGroup.objects.all(),
widget=forms.CheckboxSelectMultiple,
)
dependences = forms.ModelMultipleChoiceField(
label='Dependencias:',
queryset=Dependence.objects.all(),
widget=forms.CheckboxSelectMultiple,
)
Ajust Views.py
class SubportalDocumentUpdateView(UpdateView):
model = SubportalDocument
form_class = SubportalDocumentForm
template_name = 'portal_manager/create_document.html'
def dispatch(self, request, *args, **kwargs):
id = self.get_object().subportal_id
self.get_form().fields['servicegroups'].queryset = ServiceGroup.objects.filter(subportal_id=id)
self.get_form().fields['dependences'].queryset = Dependence.objects.filter(subportal_id=id)
return super(SubportalDocumentUpdateView, self).dispatch(request, *args, **kwargs)
def get_success_url(self):
id = self.get_object().subportal_id
return reverse_lazy('portal_manager:admin_subportal', kwargs={'id': id})
Image with the expected result but filtering the Service Groups and Dependencies:
If someone could help me or give me a clue about what is happening, I would appreciate it very much, I have been investigating for a long time and I can't get an answer.

How to use accessors in Django?

I've read previous Q and docs, however still not able to make it work..
I have the following models:
class Process(models.Model):
class Meta:
verbose_name_plural = "Processes"
name = models.CharField(max_length=120)
description = models.CharField(max_length=4)
parent_process = models.ForeignKey('self', related_name="parent_process+", on_delete=models.PROTECT, blank=True, null=True, verbose_name="parent process")
process_activities = models.CharField(max_length = 2048, blank=True, verbose_name="process activites")
owner = models.ForeignKey(User, related_name="owner+", on_delete=models.PROTECT, blank=True, null=True, verbose_name="owner")
def __str__(self):
return "{}".format(self.name)
class ControlTest(models.Model):
history = AuditlogHistoryField()
name = models.CharField(max_length=120)
description = models.CharField(max_length=120)
Now I want to use an accessor to access the name of the process and display in a table (tables.py):
class controltestTable(tables.Table):
class Meta:
hoofdproces = tables.Column(accessor='process.name')
model = ControlTest
fields = ['id',"name", "hoofdproces", "sub_process", 'description', 'control', 'delegate', 'owner', 'reviewer1', 'reviewer2', 'reviewer1_r', 'reviewer2_r', 'delegate_r',
'owner_r', 'reviewer_status', 'status', 'history', 'comments', 'review_comments', 'due_date', 'review1_due_date', 'review2_due_date', 'documentation']
template_name = "django_tables2/bootstrap-responsive.html"
Views.py:
class ControlTestView(SingleTableView, FormView, SingleTableMixin, FilterView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
queryset = kwargs.pop('object_list', None)
if queryset is None:
self.object_list = self.model.objects.all()
context['controltests'] = ControlTest.objects.all()
return context
def post(self, request, *args, **kwargs):
form = self.get_form()
print(form)
if form.is_valid():
instance = form.save(commit=True)
instance.save()
print('valid')
return self.form_valid(form)
else:
print(form.errors)
return self.form_invalid(form)
template_name = "control/ControlTest.html"
model = ControlTest
form_class = ControlTestForm
table_class = controltestTable
success_url = reverse_lazy('controltest')
However, nothing gets displayed in the hoofdproces column :(
How is that possible? What am I doing wrong?
Please help!

Django model foreignkey always defaults no matter what user is logged in

I have this django model for questions.
class Question(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, null=True, on_delete=models.SET_NULL)
question_id = models.CharField(max_length=150, null=False, default=get_id, unique=True, editable=False)
question = models.CharField(max_length=150, null=False)
question_description = FroalaField()
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=False)
question_image = models.ImageField(upload_to=get_upload_path, blank=True, null=True)
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
dynamic_link = models.CharField(max_length=225, null=False, default="")
question_type = models.CharField( max_length=50, null=False, choices=QUESTIONSTYPE_LIST)
question_status = models.CharField(max_length=150, null=False, default="unapproved")
is_active = models.BooleanField(default=False)
objects = QuestionManager()
class Meta:
ordering = ['-updated_at']
def __str__(self):
return self.question_id
def get_absolute_url(self):
kwargs = {
'questiontype': slugify(self.question_type),
'questionid': self.question_id,
'slug': slugify(self.question)
}
return reverse("questions:detail", kwargs=kwargs)
Everything seems to be working okay, except that the user user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, null=True, on_delete=models.SET_NULL)
always saves but the default which is 1. So no matter which user is logged in and in session, it always defaults to 1.
I am using classed-based-views and the user is a CustomUser.
I have the customUser set in settings.py auth_model_user as:
AUTH_USER_MODEL = 'users.CustomUser'
Here is the form for Question:
class QuestionCreationUpdateForm(forms.ModelForm):
question = forms.CharField(widget=forms.TextInput(attrs={
'class': 'frm-input',
'placeholder': _('Enter question title'),
'autocomplete': 'off'
}))
question_type = forms.ChoiceField(choices=QUESTIONSTYPE_LIST, widget=forms.Select(attrs={'class': 'frm-input'}))
question_description = forms.CharField(widget=FroalaEditor)
def __init__(self, *args, **kwargs):
super(QuestionCreationUpdateForm, self).__init__(*args, **kwargs)
class Meta:
model = Question
fields = ('question', 'question_description', 'question_type')
And the question CreateView:
# Add Question View
#method_decorator(login_required, name='dispatch')
class AskQuestionView(CreateView):
template_name = 'ask_question.html'
form_class = QuestionCreationUpdateForm
model = Question
def form_valid(self, form):
try:
return super(AskQuestionView, self).form_valid(form)
except IntegrityError:
context = {
'msg': _('We don\'t allow continues posting! Take a break. Try again later!')
}
return render(self.request, "500.html", context)
def get_success_url(self):
return self.object.get_absolute_url()
If I do a request.user in the views.py file, I always get the right user.
So why is my model behaving this odd?
As I can see, you need to assign the User object to form instance. Like this:
#method_decorator(login_required, name='dispatch')
class AskQuestionView(CreateView):
...
def form_valid(self, form):
try:
obj = form.save(commit=False)
obj.user = self.request.user
return super(AskQuestionView, self).form_valid(obj)
except IntegrityError:
context = {
'msg': _('We don\'t allow continues posting! Take a break. Try again later!')
}
return render(self.request, "500.html", context)
# ^^ consider using a 400 error response, as 500 is for server error response. 400 is for bad request
...
You are not assigning any user to Question.user. You need to assign the current user to that field.
#method_decorator(login_required, name='dispatch')
class AskQuestionView(CreateView):
template_name = 'ask_question.html'
form_class = QuestionCreationUpdateForm
model = Question
def form_valid(self, form):
try:
form.instance.user = self.request.user
return super(AskQuestionView, self).form_valid(form)
except IntegrityError:
context = {
'msg': _('We don\'t allow continues posting! Take a break. Try again later!')
}
return render(self.request, "500.html", context)
Further read Models and request.user

How to create a like functionality in django for a blog

I have to build a blog for my chess club and I would like to make a like functionality for the posts. When the user likes the post the like count increases and the post its shown in the user profile.
Here is what I made so far:
This is my post model:
class Post(models.Model):
title = models.CharField(max_length=100)
overview = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
content = HTMLField()
is_aproved = models.BooleanField(default=False)
# comment_count = models.IntegerField(default = 0)
# view_count = models.IntegerField(default = 0)
slug = models.SlugField(unique=True, blank=True)
likes = models.ManyToManyField(
settings.AUTH_USER_MODEL, blank=True, related_name='post_likes')
author = models.ForeignKey(Author, on_delete=models.CASCADE)
thumbnail = models.ImageField()
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
previous_post = models.ForeignKey(
'self', related_name='previous', on_delete=models.SET_NULL, blank=True, null=True)
next_post = models.ForeignKey(
'self', related_name='next', on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={
'id': self.id
})
def get_update_url(self):
return reverse('post-update', kwargs={
'id': self.id
})
def get_delete_url(self):
return reverse('post-delete', kwargs={
'id': self.id
})
#property
def get_comments(self):
return self.comments.all().order_by('-timestamp')
#property
def comment_count(self):
return Comment.objects.filter(post=self).count()
#property
def view_count(self):
return PostView.objects.filter(post=self).count()
And this is my view:
def post(request, id):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:3]
post = get_object_or_404(Post, id=id)
if request.user.is_authenticated:
PostView.objects.get_or_create(user=request.user, post=post)
form = CommentForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
form.instance.user = request.user
form.instance.post = post
form.save()
return redirect(reverse("post-detail", kwargs={
'id': post.pk
}))
context = {
'form': form,
'post': post,
'most_recent': most_recent,
'category_count': category_count,
'form': form
}
return render(request, 'post.html', context)
could you help me to implement this like functionality
You need another model to get liking functionality in Django. Create a like model like this-
class PostLikes(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
created = models.DateTimeField(auto_now_add=True)
then create a view to add the instance to the PostLikes model-
def like_others_post(request, post_id):
new_like, created = PostLikes.objects.get_or_create(user=request.user,
post_id=post_id)
if not created:
# you may get and delete the object as the user may already liked this
post before
We are using get or create to avoid duplication of likes. So a user may click multiple times but, a like instance is stored only once.
then add a method to Post model for getting the number of likes-
def Post(models.Model):
...
...
#property
def view_count(self):
return PostLikes.objects.filter(post=self).count()
To find out if the current user already likes the displayed post or not, in your post view-
def post(request, id):
....
....
already_liked = PostLikes.objects.filter(user=request.user, post=post).count()
if number_of_likes > 0:
already_liked = True # pass this variable to your context
else:
already_liked = False # you can make this anything other than boolean
Then by use of Javascript and {{already_liked}}, change your animation of like button in your template.

Django: How to filter ForeignKey choices by request.user with ModelFormSet

I just want to filter select field in a form, regarding a currently logged user. Every user has own categories and budgets - I want to display only a models related with a currently logged user. I've tried stuff with filtering before is_valid field, but with no result. Please, find my code below:
views.py
#login_required
def day_data_multiadd(request, no_of_lines=0):
no_of_lines = int(no_of_lines)
CostFormSet = modelformset_factory(Cost, form=DataAddForm, extra=no_of_lines)
if request.method == 'POST' and 'form' in request.POST:
formset = CostFormSet(request.POST, request.FILES)
if formset.is_valid():
for form in formset.forms:
f = form.save(commit=False)
f.user = request.user
f.save()
else:
formset = CostFormSet(queryset=Cost.objects.none())
if request.method == 'POST' and 'no_line' in request.POST:
generate_form = MultiaddGenerateForm(request.POST)
if generate_form.is_valid():
cd = generate_form.cleaned_data
return HttpResponseRedirect(reverse('core_sm:day_data_multiadd', args=(cd['formy'], )))
else:
generate_form = MultiaddGenerateForm()
return render(request, 'core_sm/costs/multi_add.html', {'formset': formset,
'no_of_lines': no_of_lines,
'generate_form': generate_form})
forms.py
class DataAddForm(forms.ModelForm):
class Meta:
model = Cost
fields = ['title', 'value', 'publish', 'category', 'budget']
exclude = ['user']
labels = {
'title': _('Tytuł'),
'value': _('Wartość'),
'publish': _('Data'),
'category': _('Kategoria'),
'budget': _('Budżet')
}
models.py
class Category(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200)
publish = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_ur(self):
return reverse('core_sm:category_detail', args=[self.id])
class Budget(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200, db_index=True)
value = models.DecimalField(decimal_places=2, max_digits=10)
publish = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('core_sm:budget_detail', args=[self.id])
class Cost(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
budget = models.ForeignKey(Budget, related_name='cost')
category = models.ForeignKey(Category, related_name='cost')
title = models.CharField(max_length=200, db_index=True)
publish = models.DateField(default=timezone.now)
created = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
value = models.DecimalField(max_digits=10, decimal_places=2)
class Meta:
ordering = ('-publish',)
def get_absolute_url(self):
return reverse('core_sm:stats_detail', args=[self.publish.year,
self.publish.strftime('%y'),
self.publish.strftime('%m'),
self.publish.strftime('%d')])
def __str__(self):
return self.title
According to the docs you can pass custom parameters to formsets forms.
class DataAddForm(forms.ModelForm):
class Meta:
model = Cost
fields = ['title', 'value', 'publish', 'category', 'budget']
exclude = ['user']
labels = {
'title': _('Tytuł'),
'value': _('Wartość'),
'publish': _('Data'),
'category': _('Kategoria'),
'budget': _('Budżet')
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
self.fields['category'].queryset = Category.objects.filter(user=user)
self.fields['budget'].queryset = Budget.objects.filter(user=user)
super(DataAddForm, self).__init__(*args, **kwargs)
views.py
formset = CostFormSet(queryset=Cost.objects.none(), form_kwargs={'user': request.user})

Categories

Resources