Django CreateView - created_by, modified_by mixin not working - django

I have followed spapas tutorial on CBV's and tried to apply a mixin on a create view. But looks like it doesn't evaluate correctly the if not form.invoice.requester for a user foreign key because it always says: RelatedObjectDoesNotExist and it points to the field evaluated in the if not line.
What can be wrong?
views.py
class AuditableMixin(object, ):
def form_valid(self, form, ):
if not form.instance.requester:
form.instance.requester = self.request.user
form.instance.modified_by = self.request.user
return super().form_valid(form)
class NewOrderView(LoginRequiredMixin, PermissionRequiredMixin, AuditableMixin, generic.CreateView):
permission_required = 'orders.add_order'
form_class = NewOrderForm
model = Order
title = 'New Order'
extra_context = {'title': title}
forms.py
class NewOrderForm(forms.ModelForm):
class Meta:
model = Order
widgets = {
'order_details': forms.Textarea,
}
exclude = (
'status',
'invoice',
'requester',
'modified_by',
)
models.py
class Order(models.Model):
STATUS_CHOICES = (
('open', 'Open'),
('inprogress', 'In Progress'),
('rejected', 'Rejected'),
('closed','Closed'),
('resolved','Resolved'),
)
subject = models.CharField(
max_length=30,
)
requester = models.ForeignKey(
User,
on_delete=models.PROTECT,
related_name='orders',
)
order_details = models.TextField(
)
created = models.DateTimeField(
auto_now_add=True,
)
updated = models.DateTimeField(
auto_now=True,
)
status = models.CharField(
max_length=12,
default='open',
choices= STATUS_CHOICES,
)
invoice = models.ForeignKey(
Invoice,
on_delete=models.PROTECT,
blank= True,
null=True,
related_name='orders',
)
modified_by = models.ForeignKey(
User,
on_delete=models.PROTECT,
related_name='orders_modified',
)
def __str__(self):
return self.subject
def get_absolute_url(self):
return reverse('Order_Detail', args=[str(self.pk)])
class Meta:
ordering = ['-created']
Thank you.

When calling the ForeignKey object on a model, you're actually telling Django to perform the query to fetch the related object. To check if the relationship exists, you should check <fieldname>_id which is the actual name of the field:
if not form.instance.requester_id:
form.instance.requester = self.request.user
That way if requester_id is None you don't perform the query, which would through the RelatedObjectDoesNotExist error.

Related

Django Inline Tabular admin: delete an object not working

I'm using Django admin.TabularInline class inorder to add multiple objects in a Foreinkey relationship as below:
admin.py:
class HeadFlowDatasetInline(admin.TabularInline):
model = HeadFlowDataset
extra = 0
class ProductAdmin(admin.ModelAdmin):
list_display = (
...
)
search_fields = (
...
)
fields = (
...
)
inlines = [HeadFlowDatasetInline]
def save_model(self, request, obj, form, change):
obj.created_by = request.user
obj.last_updated_by = request.user
obj.save()
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for instance in instances:
instance.user = request.user
instance.save()
Also these are my models for Product and HeadFlowDataset:
class Product(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False,
)
main_model = models.ForeignKey(
MainModel,
on_delete=models.SET_NULL,
null=True,
verbose_name="نام مدل اصلی پمپ",
)
usage = models.ManyToManyField(Usage)
sub_usage = models.ManyToManyField(SubUsage)
pump_type = models.ForeignKey(
PumpType,
on_delete=models.SET_NULL,
null=True,
verbose_name="تیپ پمپ",
)
pump_name = models.CharField(
max_length=255,
null=False,
blank=False,
verbose_name="نام محصول",
unique=True,
)
... # other fields not related to this question.
def __str__(self):
return self.pump_name
class HeadFlowDataset(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False,
)
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
)
head = models.FloatField()
flow = models.FloatField()
def __str__(self):
return self.product.pump_name
And for this purpose, this approach is working just fine. But the problem occurs when I'm trying to remove a HeadFlowDataset object from the add product object page. As shown in the picture below, there is a checkbox item in front of each HeadFlowDataset object, but checking it and saving does not work. I could not find any other way to make this work neither. Can anyone show me a way to do this?
because you set the commit to False then the operations don't run by default like delete and save you can use your formset.deleted_objects to iterate and delete them if have a delete permission

how to create two table objects by one viewset django rest framework

Hi i am trying to save objects in reviews table from posts table filtered by type="R"
i think i should override def create but i don't know how. please help me thanks.
my posts table
my reviews table
this is my post model
class Post(models.Model):
"""Model definition for Post."""
class Meta:
db_table = 'posts'
verbose_name = 'Post'
verbose_name_plural = 'Posts'
POST_TYPE = (
('R', 'review'),
('C', 'clubpost'),
('A', 'advertisement'),
)
title = models.CharField(
max_length=20,
null=False,
verbose_name='제목'
)
content = models.TextField(
max_length=2000,
null=False,
verbose_name='내용'
)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=False,
verbose_name='글쓴이',
)
type = models.CharField(
max_length=5,
choices=POST_TYPE,
null=True,
verbose_name='글 종류',
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name='생성 일시',
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name='수정 일시',
)
review model
class Review(models.Model):
class Meta:
db_table = 'reviews'
verbose_name = 'Review'
verbose_name_plural = 'Reviews'
post = models.OneToOneField(
Post,
on_delete=models.CASCADE,
related_name="review",
)
post serializer
class PostSerializer(ModelSerializer):
author = UserAbstractSerializer(read_only=True)
class Meta:
model = Post
fields = [
'id',
'title',
'content',
'author',
'type',
'created_at',
'updated_at'
]
extra_kwargs = {
'title': {
'error_messages': {
'required': '제목을 입력해주세요.',
}
},
'content': {
'error_messages': {
'required': '내용을 입력해주세요.',
}
}
}
review serializer
class ReviewSerializer(ModelSerializer):
post_id = PostSerializer(read_only=True)
class Meta:
model = Post
fields = [
'id',
'post_id',
]
review viewset
class ReviewViewSet(PostViewSet):
queryset = Post.objects.filter(type="R"),
serializer_class = ReviewSerializer
def perform_create(self, serializer):
return serializer.save(author=self.request.user, type="R")
i think i should override create method in review viewset but i dont know how to write
wanna figure out how to create two table objects by one viewset django rest framework

Djnago Form getting Error while edit record

I am getting Issue while edit a record based on CHatquestion ID, if option is null then i need to add a record based on same chatquestion id, if chatqustion id exist in option it will work,
i am trying to multiple way to solve this issue but still can't find solution.
Models.py # thease are all 3 models
class Problem(models.Model):
Language = models.IntegerField(choices=Language_CHOICE, default=1)
type = models.CharField(max_length=500, null=True, blank=True)
def __str__(self):
return self.type
class ChatQuestion(models.Model): # Eding record based on chatquestion id
question = RichTextField(null=True, blank=True)
problem_id = models.ForeignKey(
Problem,
models.CASCADE,
verbose_name='Problem',
)
def __str__(self):
return self.question
is_first_question = models.BooleanField(default=False)
class Option(models.Model):
option_type = models.CharField(max_length=250, null=True, blank=True)
question_id = models.ForeignKey(
ChatQuestion,
models.CASCADE,
verbose_name='Question',
null=True,
blank=True
)
problem=models.ForeignKey(
Problem,
models.CASCADE,
verbose_name='Problem',
null=True,
blank=True
)
next_question_id = models.ForeignKey(ChatQuestion, on_delete=models.CASCADE, null=True, blank=True,
related_name='next_question')
def __str__(self):
return self.option_type
forms.py
class EditQuestionForm(forms.ModelForm):
class Meta:
model = ChatQuestion
fields =('question','problem_id')
class EditOptionForm(forms.ModelForm):
class Meta:
model = Option
fields =('option_type',)
views.py
def question_edit(request,id=None):
if id is not None:
queryset = get_object_or_404(ChatQuestion,pk=id)
queryset1=get_object_or_404(Option,question_id=queryset )
else:
queryset = None
queryset1 = None
if request.method=="POST":
form = EditQuestionForm(request.POST ,instance=queryset)
form1=EditOptionForm(request.POST, instance=queryset1)
if form.is_valid() and form1.is_valid():
question=form.cleaned_data['question']
option_type=form1.cleaned_data['option_type']
if id:
queryset.question=question
queryset.save()
queryset1.option_type=option_type
queryset1.save()
messages.success(request,'Sucessful')
return redirect('/fleet/list_chatbot')
else:
print(form.errors)
messages.error(request,'Please correct following',form.errors)
elif id:
form = EditQuestionForm(instance=queryset)
form1=EditOptionForm(instance=queryset1)
if not queryset1:
form1=EditOptionForm()
else:
form = EditQuestionForm()
form1=EditOptionForm()
context={
'form':form,
'form1':form1
}
return render(request,'chatbot/question_edit.html',context=context)

I want to retrieves all Post objects which have at least one followUser whose user=request.user

FieldError at /en/account/profile/follow_list/
Cannot resolve keyword 'followidf' into field. Choices are: author, author_id,
This spanning can be as deep as you’d like.
It works backwards, too. While it can be customized, by default you refer to a “reverse” relationship in a lookup using the lowercase name of the model.
This example retrieves all Post objects which have at least one followUser whose user=request.user
class Post(models.Model):
title = models.CharField(max_length=250)
excerpt = models.TextField()
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='blog_posts')
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
favourite = models.ManyToManyField( User, related_name='favouriteUser', default=None, blank=True)
avatar = models.ImageField( upload_to=user_directory_path, default='users/avatar.png')
bio = models.TextField(max_length=5500, blank=True)
fullName = models.CharField(max_length=221, blank=True, default=rand_slug(5) )
dr = models.BooleanField( default=False )
slug = models.SlugField(max_length=250, unique=True, blank=True, default=rand_slug(8))
class followUser(models.Model):
folPr = models.ForeignKey(Profile, related_name='followfp',on_delete=models.CASCADE, default=None, blank=True)
follUser = models.ForeignKey(User, related_name='followidf',on_delete=models.CASCADE, default=None, blank=True)
vote = models.BooleanField(default=True)
publish = models.DateTimeField(default=timezone.now)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.follUser.username
# login_required
def follow_list(request):
new2 = Post.objects.filter( followidf__user =request.user )
return render(request, 'accounts/follow_list.html', {'new': new2 } )
try this code
#login_required
def follow_list(request):
follow = Profile.objects.filter( followfp__follUser= request.user)
user =[]
for d in follow:
user +=[d.user]
print(d.user.id)
new = Post.objects.filter( author__in = user)
return render(request, 'accounts/followList.html', {'new': new } )
try this maybe id_list = User.objects.prefetch_related('followidf_set).filter(id=request__user__id).values_list('id',flat=True).all() Post.objects.filter(user__id__in=id_list)
Post.objects.filter( followidf__user__author =request.user )
or,
Post.objects.filter( folluser__user__author =request.user )
you can try this if you getting author as request.user.
or can change this part __author , what you getting as request.user .
this code work but I don't want used loop
#login_required
def follow_list(request):
follow = Profile.objects.filter( followfp__follUser= request.user)
user =[]
for d in follow:
user +=[d.user]
print(d.user.id)
new = Post.objects.filter( author__in = user)
return render(request, 'accounts/followList.html', {'new': new } )

Multiple generic class based DetailView's for the SAME model

I am attempting to use two detail views that will render different templates for the same model, at different URLs of course. Is it possible to have different generic detail views for the same model? If not I'll just have to write my own I suppose. All my detail views route to the absoluteurl but in this case I want each detail view to route to the template I have defined in the class.
I used the method below to successfully create multiple list views and update views, but it just doesn't work on detail views, I always end up at "course_detail" even though I declared "course_detail_producer_view."
models.py
class Course(models.Model):
class Meta:
verbose_name = "Course"
verbose_name_plural = "Courses"
ordering = ['start_time']
pub_partner_choices = [
("company1", "company1"),
('company2', 'company2'),
]
status_choices = [
('hold', 'Hold'),
('editorial', 'Editorial'),
('approved', 'Approved'),
('cancelled', 'Cancelled'),
]
title = models.CharField(max_length=200)
slug = AutoSlugField(max_length=100, help_text="course title",
populate_from=['title', 'date'], unique=True, )
start_time = models.TimeField(blank=True, null=True)
end_time = models.TimeField(blank=True, null=True)
date = models.DateField(blank=True, null=True)
new_course = models.BooleanField(default=False)
new_instructor = models.BooleanField(default=False)
katacoda = models.BooleanField(default=False)
jupyterhub = models.BooleanField(default=False)
released = models.BooleanField(default=False)
status = models.CharField(max_length=50,
choices=status_choices,
blank=False
)
pub_partner = models.CharField(max_length=50,
choices=pub_partner_choices,
blank=False)
course_notes = models.TextField(max_length=500,
blank=True,
)
producer_notes = models.TextField(max_length=500, blank=True)
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False
)
producer = models.ManyToManyField(Producer,
related_name="course",
blank=True,
)
def get_absolute_url(self):
"""Return URL to detail page of a Course"""
return reverse(
"course_detail",
kwargs={"slug": self.slug}
)
def __str__(self):
date_time = f"{self.date} {self.start_time}"
return f"{self.title} : {date_time}"
urls.py
path(
'courses/<str:slug>/',
CourseDetail.as_view(),
name='course_detail'
),
path(
'courses/producer-view/<str:slug>/',
CourseDetailProducerView.as_view(),
name='course_detail_producer_view'
),
views.py
class CourseDetail(LoginRequiredMixin, DetailView):
queryset = Course.objects.all()
template_name = 'lots_app/course_detail.html'
class CourseDetailProducerView(LoginRequiredMixin, DetailView):
queryset = Course.objects.all()
template_name = 'lots_app/course_detail_producer_view.html'
My problem was being caused by an UpdateView that was using reverse_lazy to get the absolute_url. It turns out there was no problems with the DetailViews, just how I was trying to get to them (whoops!) The solution was to override get_success_url(). The now corrected UpdateView looks like this:
class CourseUpdateProducerView(LoginRequiredMixin, UpdateView):
form_class = CourseFormProducerView
model = Course
template_name = 'lots_app/course_form_producer_view.html'
extra_context = {"update": True}
def get_success_url(self, **kwargs):
"""Return the URL to redirect to after processing a valid form."""
url = reverse_lazy('course_detail_producer_view',
kwargs={"slug": self.object.slug})
return url