I want to deal with foreignKey with a modelForm and it raise this error:
ValueError at /3/
The view main.views.ProductDetailView didn't return an
HttpResponse object. It returned None instead.
the problem is on the Wilaya and commune fields, because when i remove them all works fine.
in views.py
class ProductDetailView(ModelFormMixin, DetailView):
model = Produit
context_object_name = 'produit'
form_class = CheckoutCreateForm
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context["form"] = self.get_form()
context["wilayas"]= Wilaya.objects.all()
context["communes"]= Commune.objects.all()
return context
def post(self, request, *args, **kwargs):
# self.object = self.get_object()
# form = self.get_form()
form = CheckoutCreateForm(request.POST)
if form.is_valid():
checkout = form.save(commit=False)
checkout.produit = self.get_object()
checkout.prix = self.get_object().price
checkout.save()
wilaya = form.cleaned_data['wilaya']
commune = form.cleaned_data['commune']
quantity = form.cleaned_data['quantity']
nom_du_client = form.cleaned_data['nom_du_client']
prenom_du_client = form.cleaned_data['prenom_du_client']
adresse_du_client = form.cleaned_data['adresse_du_client']
print('jusque la cv')
try:
form = CheckoutCreateForm()
return redirect(f'/{self.get_object().pk}')
except:
return redirect('/')
in models.py
class Wilaya(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Commune(models.Model):
Wilaya = models.ForeignKey(Wilaya, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Checkout(models.Model):
produit = models.ForeignKey('Produit', on_delete=models.CASCADE)
prix = models.IntegerField(default=0)
nom_du_client = models.CharField(max_length=40)
prenom_du_client = models.CharField(max_length=40)
adresse_du_client = models.CharField(max_length=40)
date_added = models.DateTimeField(auto_now_add=True)
wilaya = models.ForeignKey(Wilaya, on_delete=models.SET_NULL, null=True, blank=True)
commune = models.ForeignKey(Commune, on_delete=models.SET_NULL, null=True, blank=True)
quantity = models.PositiveIntegerField(default=1)
confirmer = models.BooleanField(default=False)
def __str__(self):
return str(self.produit)
in forms.py
from django import forms
from .models import Checkout, Commune , Wilaya
class CheckoutCreateForm(forms.ModelForm):
class Meta:
model = Checkout
fields = ['nom_du_client', 'prenom_du_client','adresse_du_client', 'quantity', 'wilaya', 'commune']
in html file :
<form class="card-body" method='POST' id="checkoutForm" >
{% csrf_token %}
<!--Grid row-->
<div class="row">
<!--Grid column-->
<div class="col-md-6 mb-2">
<!--firstName-->
<div class="md-form ">
<input type="text" name="nom_du_client" id="firstName" class="form-control">
<label for="nom_du_client" class="">First name</label>
</div>
.... rest of the form
<button class="btn btn-primary btn-lg btn-block" type="submit">Continue to checkout</button>
</form>
The error is pretty self-explanatory:
The view main.views.ProductDetailView didn't return an HttpResponse object. It returned None instead.
If you look at the reduced version of your code:
class ProductDetailView(ModelFormMixin, DetailView):
def post(self, request, *args, **kwargs):
...
if form.is_valid():
...
try:
...
return redirect(f'/{self.get_object().pk}')
except:
return redirect('/')
You can notice that the method post() returns None if the form is not valid.
One possible solution is to have a return redirect(...) at the end as well:
class ProductDetailView(ModelFormMixin, DetailView):
def post(self, request, *args, **kwargs):
...
if form.is_valid():
...
try:
...
return redirect(f'/{self.get_object().pk}')
except:
pass
return redirect('/')
Related
When I query all the comments of the post, I want to return the user's username.
My two Models:
class Comment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
post = models.ForeignKey(
Post, on_delete=models.CASCADE, null=False, blank=False)
title = models.TextField()
date = models.DateField(auto_now=True)
class User(AbstractUser):
objects = UserManager()
username = models.CharField(max_length=60, unique=True)
avi_pic = models.ImageField(
_('avi_pic'), upload_to=aviFile, null=True, blank=True)
My Comments Serializer:
class CommentSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField('get_username_from_user')
avi_pic = serializers.SerializerMethodField('get_avi_pic')
class Meta:
model = Comment
fields = '__all__'
def get_username_from_user(self, comment):
username = comment.user.username
return username
def get_avi_pic(self, comment):
request = self.context['request']
avi_pic = comment.user.avi_pic.url
return request.build_absolute_uri(avi_pic)
My Comments View:
class CommentView(APIView):
authentication_class = [authentication.TokenAuthentication]
permission_class = [permissions.IsAuthenticated]
serializer_class = CommentSerializer
# Get all comments from current post
def get(self, request):
post_id = request.data.get('id')
post = Post.objects.get(id=post_id)
comment = Comment.objects.filter(post=post).values()
serializer = CommentSerializer(comment)
return Response(serializer.data, status=status.HTTP_200_OK)
In my console I get: 'QuerySet' object has no attribute 'user'
Appreciate any help!!
In views.py:
comment = Comment.objects.filter(post=post)
In serializer.py:
def get_username_from_user(self, comment):
username = comment.user.username
return username
In views.py:
def get(self, request):
...
serializer = CommentSerializer(comment, many=True)
...
In my humble opinion, your problem is not having a ForeignKey for the "User" model, meaning whatever model you are trying to render doesn't have a column named 'user'. I'd do something like this:
models.py
class User(AbstractUser):
pass
def __str__(self):
return f"{self.username}"
class Comment(models.Model):
comment = models.TextField(max_length=300, null=True)
creation_date = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(User, on_delete=models.CASCADE)
whatever_name = models.ForeignKey(whatever_model_to_relate, on_delete=models.CASCADE, related_name="comments")
forms.py
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ['comment']
widgets = {
'comment': forms.Textarea(attrs={'rows':4, 'cols':100}),
}
views.py
#login_required
def whatever_function(request, id):
whatever_name = whatever_related_model.objects.get(id=id)
return render(request, "template.html", {
"whatever_name_for_template": whatever_name,
"commentform": CommentForm()
})
template.html
{% for comment in whatever_related_model.comments.all %}
<div class="card p-1 m-2 col-lg-12 col-sm-12">
<div class="card-body">
<h5 class="card-title">{{ comment.user }}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{ comment.creation_date }}</h6>
{{ comment.comment }}
</div>
</div>
{% endfor %}
Hopefully I didn't get sidetracked from your question.
I want to add review function in movie_detail.html, but I don't know how to query comments and map to movie_detail.It returns Reverse for 'add_review' with arguments '('',)' not found error.
My url.py:
urlpatterns = [
path('', MovieList.as_view(), name='movie_list'),
path('<int:pk>', MovieDetail.as_view(), name='movie_detail'),
path('search/', MovieSearch.as_view(), name='movie_search'),
path('addreview/<int:id>/', views.add_review, name='add_review'),
]
My model.py:
class Movie(models.Model):
title = models.CharField(max_length=200)
actors = models.CharField(max_length=500, null=True)
poster_url = models.CharField(max_length=200)
director = models.CharField(max_length=200, default='')
score = models.FloatField()
genres = models.CharField(max_length=200)
language = models.CharField(max_length=200, default='English')
durations = models.IntegerField(default=0)
regions = models.CharField(max_length=200, default='')
release_date = models.DateField(default=timezone.now)
description = models.TextField(max_length=1000, default='')
year = models.IntegerField(default=2000)
views_count = models.IntegerField(default=0)
created = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
def genres_as_list(self):
genre_list = self.genres.split('/')
return genre_list
def actors_as_list(self):
return self.actors.split('/')
class Review(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
comments = models.TextField(max_length=1000)
rating = models.FloatField(default=0)
data_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username
my view.py:
class MovieDetail(DetailView):
model = Movie
template_name = "main/movie_detail.html"
def get_object(self):
object = super().get_object()
object.views_count += 1
object.save()
return object
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['links'] = MovieLinks.objects.filter(movie=self.get_object())
context['related_movies'] = Movie.objects.filter(genres__in=self.get_object().genres_as_list()).order_by(
'created')[0:6]
# context['reviews'] = Review.objects.filter(id=self.kwargs['pk'])
return context
class MovieSearch(ListView):
model = Movie
paginate_by = 20
template_name = "main/movie_list.html"
def get_queryset(self):
query = self.request.GET.get('query')
if query:
object_list = self.model.objects.filter(title__icontains=query)
else:
object_list = self.model.objects.none()
return object_list
#login_required
def add_review(request, id):
movie = Movie.objects.get(id=id)
if request.method != "POST":
form = ReviewForm(request.POST or None)
if form.is_valid():
data = form.save(commit=False)
data.comment = request.POST["comment"]
data.rating = request.POST["rating"]
data.user_id = request.user.pk
data.movie_id = movie.pk
data.save()
return redirect("main:movie_detail", id)
else:
form = ReviewForm()
context = {"form": form}
return render(request, 'main/movie_detail.html', context)
my movies_detail.html review part:
<section class="comments">
<h3>Comment</h3>
<div class="card">
<div class="card-body">
<h3 class="text-center">Add Review</h3>
<form method="POST" action="{% url 'main:add_review' movie.id%}">
{% csrf_token %}
<label for="comment">Review</label>
<textarea name="comment" id="comment" cols="30" rows="5" class="form-control"></textarea>
<label for="rating">Rating</label>
<input type="text" name="rating" class="form-control">
<br>
<input type="submit" class="btn btn-danger" value="Add Review">
</form>
</div>
</div>
I want add the review function and I code the add_review in view.py by some tutorial.But I don't know how to fix it.
You are not passing the movie object to template, so movie.id evaluates to an empty to string, which causes the exception you are seeing.
Try this:
#login_required
def add_review(request, id):
movie = Movie.objects.get(id=id)
...
context = {"form": form, "movie": movie}
return render(request, 'main/movie_detail.html', context)
Edit: alternatively, you can just set action="" as shah sawood pointed out in his answer.
On a side note: Welcome to Stack Overflow! Next time, please post the full stacktrace, that increases your chances of getting an answer to your problem :)
Note
When you want to post data a view that it renders you need not to specify action but rather leave as action=""
You're getting the error because you're not passing a movie to the context in the last 2 lines of add_review. You need to update it to
context = {"form": form, "movie": movie}
return render(request, 'main/movie_detail.html', context)
I am new to django, and I am creating a vacation application. I want to be able to when I create a new trip, the user that created the trip becomes a member of that trip.
here is my models.py file:
class Trip(models.Model):
trip_name = models.CharField(max_length=255,unique=False)
start_date = models.DateField(default=datetime.date.today)
end_date = models.DateField(default=datetime.date.today)
slug = models.SlugField(allow_unicode=True,unique=True)
members = models.ManyToManyField(User,through='TripMember')
def __str__(self):
return self.trip_name
def save(self,*args,**kwargs):
self.slug = slugify(self.trip_name)
super().save(*args,**kwargs)
def get_absolute_url(self):
return reverse('trips:single',kwargs={'slug':self.slug})
class Meta:
ordering = ['start_date']
class TripMember(models.Model):
trip = models.ForeignKey(Trip,null=True,related_name='memberships',on_delete=models.SET_NULL)
user = models.ForeignKey(User,null=True,related_name='user_trips',on_delete=models.SET_NULL)
def __str__(self):
return self.user.username
class Meta:
unique_together = ('trip','user')
this is my forms.py file:
class TripCreateForm(forms.ModelForm):
class Meta:
fields = ('trip_name','start_date','end_date')
model = Trip
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["trip_name"].label = "Trip Name"
self.fields["start_date"].label = "Start Date"
self.fields["end_date"].label = "End Date"
here is my views.py file:
class CreateTrip(CreateView):
form_class = TripCreateForm
template_name = 'trips/trip_form.html'
and my trip_form.html page:
<form action="{% url 'trips:create' %}" method="post" id='tripForm'>
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-primary btn-large" value="Create">
</form>
Where would I put the code to set the user as a tripmember and why?Also, if there is a better way to have set this up please let me know! I was gonna put it in the save part of the model but I am not quite sure if that is correct. Thanks!
You can override the form_valid() method of the CreateTrip class in your view:
def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
# add the current user to the members list of the trip
user = self.request.user
self.object.members.add(user)
return super().form_valid(form)
Models
attendance_choices = (
('absent', 'Absent'),
('present', 'Present')
)
class Head_of_department(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
email = models.CharField(max_length=30)
def __str__(self):
return self.first_name
class Employee(models.Model):
first_name = models.CharField(max_length=200, unique=True)
last_name = models.CharField(max_length=200, unique=True)
head_of_department = models.ForeignKey('Head_of_department', on_delete=models.SET_NULL, blank=True, null=True)
email = models.EmailField(max_length=100)
def __str__(self):
return self.first_name + ' ' + self.last_name
class Attendance(models.Model):
head_of_department = models.ForeignKey('Head_of_department', on_delete=models.SET_NULL, blank=True, null=True)
employee = models.ForeignKey('Employee', on_delete=models.CASCADE, )
attendance = models.CharField(max_length=8, choices=attendance_choices, blank=True)
Views
class Attendancecreate(CreateView):
model = Attendance
fields = ['employee']
success_url = '/dashboard/'
def get_context_data(self,** kwargs):
context = super(Attendancecreate, self).get_context_data(**kwargs)
context['formset'] = AttendanceFormset(queryset=Attendance.objects.none(), instance=Head_of_department.objects.get(email=email), initial=[{'employee': employee} for employee inself.get_initial()['employee']])
context['attendance_form'] = Attendanceform()
email = self.request.user.email
hod = Head_of_department.objects.get(email=email)
context["employees"] = Employee.objects.filter(head_of_department =hod)
return context
def get_initial(self):
email = self.request.user.email
hod = Head_of_department.objects.get(email=email)
initial = super(Attendancecreate , self).get_initial()
initial['employee'] = Employee.objects.filter(head_of_department=hod)
return initial
def post(self, request, *args, **kwargs):
formset = AttendanceFormset(queryset=Attendance.objects.none(), instance=Head_of_department.objects.get(email=email), initial=[{'employee': employee} for employee inself.get_initial()['employee']))
if formset.is_valid():
return self.form_valid(formset)
def form_valid(self, formset):
instances = formset.save(commit=False)
for instance in instances:
instance.head_of_department = get_object_or_404(Head_of_department, email=self.request.user.email)
instance.save()
return HttpResponseRedirect('/dashboard/')
def form_invalid(self, formset):
print ('errors')
print (formset.errors)
Forms
class Attendanceform(ModelForm):
class Meta:
model = Attendance
fields = ('employee','attendance','hod')
AttendanceFormset = inlineformset_factory(Head_of_department,Attendance,fields=('attendance',))
Template
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
<br><br>
{% endfor %}
Error
Below shown square brackets was printed in the console when I used print(formset.errors)
[]
How to pass employees as initial values for attendance model as shown below in the images, employees will be rendered and rendered values have to be passed as employee in attendance model.
Is there any workaround with modelformset or inlineformset ? I can't get it right with the views I have included in the question .
I was missing request.post ,
class Attendancecreate(CreateView):
...
def post(self, request, *args, **kwargs,):
formset = AttendanceFormset(request.POST,queryset=Attendance.objects.none(), instance=Head_of_department.objects.get(email=self.request.user.email), initial=[{'employee': employee} for employee in self.get_initial()['employee']])
if formset.is_valid():
return self.form_valid(formset)
Template
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form.employee.initial }} {{ form.employee}} {{ form.attendance }}
<br><br>
{% endfor %}
I am currently working on a blog for a project, and i want to add in a comment section for each post in the DetailView. My code seems fine, however i keep getting a "Page not Found(404) error". I am thinking it may be my url pattern but i cannot seem to figure out what i am doing wrong.
error given
url.py
urlpatterns[
path('blog/post/<int:pk>/', views.PostDetailView.as_view(),name='post_detail'),
path('blog/post/<int:pk>/comment/', views.MyFormView.as_view(), name='my_form_view_url'),
]
forms.py
class CommentForm(forms.ModelForm):
class Meta():
model = Comment
fields = ('text',)
widgets = {
'text': forms.Textarea(attrs={'class':'ediable medium-editor-textarea'})
}
views.py
class PostDetailView(DetailView):
model = Post
template_name = 'carsforsale/post_detail.html'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['form'] = CommentForm()
return context
class MyFormView(SingleObjectMixin,FormView):
template_name = 'carsforsale/post_detail.html'
form_class = CommentForm
model = Comment
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super().post(request, *args, **kwargs)
def get_success_url(self):
return reverse('carsforsale:post_detail', kwargs={'pk': self.object.pk})
post_detail.html
this is the form inside of the post_detail.html
<form method="POST" action="{% url 'carsforsale:my_form_view_url' pk=post.pk %}">
{% csrf_token %}
<div class="form-group">
{% render_field form.text class="form-control text" rows=3 %}
</div>
<input type="submit" class="btn btn-primary" value="Comment" />
</form>
These are my Post and Comment models
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete= models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def approve_comments(self):
return self.comments.filter(approved_comment=True)
def get_absolute_url(self):
return reverse("post_list")
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey('carsforsale.Post', related_name='comments', on_delete = models.CASCADE)
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def get_absolute_url(self):
return reverse("carsforsale:post_detail",kwargs={'pk':self.pk})
def __str__(self):
return self.text
Presumably the pk in the URL for MyFormView refers to the post the comment is going to be attached to. But the view itself has a model attribute of Comment, so that is the model that Django tries to load. The comment with that pk doesn't exist, hence the error.
You will need to override get_object to do the query directly and return the object. You will also need to override form_valid to associate the new comment with that post.
def get_object(self, **kwargs):
return get_object_or_404(Post, pk=self.kwargs["pk"]
def form_valid(self, form):
form.instance.post = self get_object()
return super().form_valid(form)