So I have this form which extends the User and I just want to allow the student to create and account and be able to select the courses from the course list.But when I try, I get the error:
__init__() takes 1 positional argument but 2 were given
I can't find any solution to this yet. I need some advice.
These are my files:
{% block body %}
<div class="row">
<div class="col-md-8 col-sm-10 col-12">
<h2>Sign up as a {{ user_type }}</h2>
<form method="post" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
{{ form }}
<button type="submit" class="btn btn-success">Sign up</button>
</form>
</div>
</div>
{% endblock %}
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
path('signup/', views.StudentSignUpView, name='signup')
class StudentSignUpForm(UserCreationForm):
attended_courses = forms.ModelMultipleChoiceField(
queryset=Course.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=True
)
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_student = True
user.save()
student = Student.objects.create(user=user)
student.attended_courses.add(*self.cleaned_data.get('attended_courses'))
return user
class StudentSignUpView(CreateView):
model = User
form_class = StudentSignUpForm
template_name = 'signup_form.html'
def get_context_data(self, **kwargs):
kwargs['user_type'] = 'student'
return super().get_context_data(**kwargs)
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect('index')
Class-based views need to be referenced in urls.py via their as_view method.
path('signup/', views.StudentSignUpView.as_view(), name='signup')
Related
I was getting that same error while click the like button, But the error was solved..
again after creating comment view and its other staff I'm getting that error again...When I click the comment button then the error appears..I'm very new to Django,,, help me please..
My project models.py, template page, urls.py, views.py are attached herewith
**models.py**
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Blog(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200, verbose_name="Put a Title")
blog_content = models.TextField(verbose_name="What is on your mind")
blog_image = models.ImageField(upload_to="blog_images", default = "/default.png")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Comment(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_comment" )
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_comment")
comment = models.TextField()
comment_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.comment
class Like(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_liked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_liked")
class Unlike(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_unliked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_unliked")
**blog_page.html**
{% extends "main.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div style="text-align:center;">
<h2>{{blog.title}}</h2>
<img src="{{blog.blog_image.url}}" alt="" width="630px" height="300px">
</div>
<div style="text-align:center;">
{{blog.blog_content|linebreaks}}
</div>
{% if not liked and not unliked %}
<h4> Like </h4>
<h4>Unlike</h4>
{% elif unliked %}
<h4> Like </h4>
{% elif liked %}
<h4>Unlike</h4>
{% endif %}
<div>
<h4>
Comments:
</h4>
{% for comment in comments %}
<div>
{{ user }} <br>
<h5>{{ comment }}</h5>
</div>
{% endfor %}
<!-- <h6>Add your comment:</h6> -->
<form action="" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<a class="btn btn-sm btn-info" href="{% url 'comment' %}">Comment</a>
</form>
</div>
{% endblock content %}
**urls.py**
from django.urls import path
from blog_app import views
urlpatterns = [
path("", views.home, name='home'),
path("blog_page/<str:pk>/", views.blog_view, name='blog_page'),
path("like/<str:pk>/", views.like, name="like"),
path("unlike/<str:pk>/", views.unlike, name="unlike"),
path("comment/", views.comment, name="comment"),
]
**views.py**
from django.shortcuts import render
from . models import Blog, Comment, Like, Unlike
from . forms import CommentForm
# Create your views here.
def home(request):
blogs = Blog.objects.all()
context = {'blogs': blogs}
return render(request, 'blog_app/home.html', context)
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
form = CommentForm()
comments = Comment.objects.filter(blog=blog)
context = {"blog": blog, "comments": comments, "form":form}
return render(request, 'blog_app/blog_page.html', context)
def like(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
liked, like = Like.objects.get_or_create(blog=blog, user=user)
context = {"liked" : liked, "blog": blog }
return render(request, "blog_app/blog_page.html", context)
def unlike(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
unliked, unlike = Unlike.objects.get_or_create(blog=blog, user=user)
context = {"unliked" : unliked, 'blog': blog}
return render(request, "blog_app/blog_page.html", context)
def comment(request):
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
context = {}
return render(request, "blog_app/blog_page.html", context)
Your comment button is just a link, is it normal ? I think, you want to submit your form when you click on?
<div>
<h4>
Comments:
</h4>
{% for comment in comments %}
<div>
{{ user }} <br>
<h5>{{ comment }}</h5>
</div>
{% endfor %}
<!-- <h6>Add your comment:</h6> -->
<form action="{% url 'comment' %}" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<button type="submit" class="btn btn-sm btn-info">Comment</button>
</form>
</div>
And i think, your problem occured because you dispolay this template from comment view without set blog in context data.
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
form = CommentForm()
comments = Comment.objects.filter(blog=blog)
context = {"blog": blog, "comments": comments, "form":form}
return render(request, 'blog_app/blog_page.html', context)
def comment(request):
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return redirect("blog_page", pk=form.instance.blog.pk)
return HttpResponse(status_code=400) # error case
else:
return HttpResponse(status_code=501) # try to GET page
Better solution is to pass blog pk in the url for being able to render page with error:
path("blog/<int:pk>/comment/", views.comment, name="comment")
<form action="{% url 'comment' blog.pk %}" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<button type="submit" class="btn btn-sm btn-info">Comment</button>
</form>
def comment(request, pk):
blog = get_object_or_404(Blog, pk=pk)
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return redirect("blog_page", pk=blog.pk)
return render(request, "...", {"blog": blog, "form": form})
I'm trying to implement a feature where logged in users can comment on a blog post, but I'm a little stuck with the comments appearing on the page.
I can type in the comment and submit them. However, this is always returning a GET request. I tried adding method='post' to both the form and button tags, but this resulted in the following:
Method Not Allowed (POST): /post/1/
Method Not Allowed: /post/1/
I'm not really sure what the problem is. Any help would be much appreciated. Code snippets below.
post_detail.html with comment section:
<div class="content-section">
<legend class="border-bottom">Comments:</legend>
{% if user.is_authenticated %}
<form id="commentForm">
{% csrf_token %}
<fieldset class="form-group">
<div class="row">
<!-- <div class="col"></div> -->
<div class="col-1 text-right">
<img class="img-comment" src="{{ user.profile.image.url }}">
</div>
<div class="col-9">
<textarea type="text" id="commentIn" name="comment"
placeholder="Your comment..." required></textarea>
</div>
<div class="col"></div>
</div>
<div class="row">
<div class="col-10 text-right">
<button id="commentBtn" name="comment_button"
class="btn btn-outline-info" type="submit">Comment</button>
</div>
<div class="col"></div>
</div>
<hr>
</fieldset>
</form>
{% endif %}
<div id="commentDiv">
{% for cmnt in comments_list %}
<img class="img-comment"
src="{{cmnt.commentator.profile.image.url }}">
<a class="mr-2" >{{ cmnt.commentator }}</a>
<p class="article-content">{{ cmnt.comment }}</p>
<hr>
{% endfor %}
</div>
</div>
urls.py in blog app
urlpatterns = [
path('post/<int:pk>/', PostDetailView.as_view(), name="post-detail"),
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.ManyToManyField(User, related_name='like')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Comment(models.Model):
commentator = models.ForeignKey(User, on_delete=models.CASCADE)
blog = models.ForeignKey(Post, on_delete=models.CASCADE)
comment = models.CharField(max_length=200)
date_added = models.DateTimeField(default=timezone.now)
class meta:
verbose_name_plural = 'comments'
def __str__(self):
return self.comment
views.py
class PostDetailView(DetailView):
model = Post
form = CommentForm()
def get_context_data(self, **kwargs):
if self.request.method == 'GET':
print('Render a blank form for users to fill out')
print(self.form)
elif self.request.method == 'POST':
print('Get the data from the POST request')
print(self.form)
status = 0
if self.request.user in self.object.likes.all():
status = 1
context = super().get_context_data(**kwargs)
context['comments_list'] = Comment.objects.filter(blog=self.object)
context['status'] = status
return context
and finally, the form itself:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['comment']
Don't mix class-based-view with method-based-view. You have to provide function that reads method and behave as it should. For get you usually will have built-in solutions, like form_class - in post() you can call it via form = self.get_form(). It generally looks like this:
class PostDetailView(DetailView):
model = Post
form_class = CommentForm
def post(self, request, *args, **kwargs):
form = self.get_form()
print('Get the data from the POST request')
print(form)
def get_context_data(self, **kwargs):
status = 0
if self.request.user in self.object.likes.all():
status = 1
context = super().get_context_data(**kwargs)
context['comments_list'] = Comment.objects.filter(blog=self.object)
context['status'] = status
return context
Another things to check ie. here: https://stackoverflow.com/a/45661979/12775662
I need help with my code. I have read through the code several times and I didn't see anything wrong with it.
The user is expected to submit a job application and redirect the user to the dashboard, but it did not submit the job application neither does it direct the user to the dashboard.
here is my code:
mode.py
from django.db import models
from django.contrib.auth.models import User
class Job(models.Model):
title = models.CharField(max_length=255)
short_description = models.TextField()
long_description = models.TextField(blank=True, null=True)
created_by = models.ForeignKey(User, related_name='jobs', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
changed_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Application(models.Model):
job = models.ForeignKey(Job, related_name='applications', on_delete=models.CASCADE)
content = models.TextField()
experience = models.TextField()
created_by = models.ForeignKey(User, related_name='applications', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
Views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .forms import AddJobForm, ApplicationForm
from .models import Job
def job_detail(request, job_id):
job = Job.objects.get(pk=job_id)
return render(request, 'jobs/job_detail.html', {'job': job})
#login_required
def add_job(request):
if request.method == 'POST':
form = AddJobForm(request.POST)
if form.is_valid():
job = form.save(commit=False)
job.created_by = request.user
job.save()
return redirect('dashboard')
else:
form = AddJobForm()
return render(request, 'jobs/add_job.html', {'form': form})
#login_required
def apply_for_job(request, job_id):
job = Job.objects.get(pk=job_id)
if request.method == 'POST':
form = ApplicationForm(request.POST)
if form.is_valid():
application = form.save(commit=False)
application.job = job
application.created_by = request.user
application.save()
#create_notification(request, job.created_by, 'application', extra_id=application.id)
return redirect('dashboard')
else:
form = ApplicationForm()
return render(request, 'jobs/apply_for_job.html', {'form': form, 'job': job})
forms.py
from django import forms
from .models import Job, Application
class AddJobForm(forms.ModelForm):
class Meta:
model = Job
fields = ['title','short_description','long_description']
class ApplicationForm(forms.ModelForm):
class Meta:
model = Application
fields = ['content', 'experience']
apply_for_job.html
{% extends 'core/base.html' %}
{% block content %}
Apply for job - {{ job.title }}
<form method="post" action=".">
{% csrf_token %}
{% if form.errors %}
{% for error in form.errors %}
<div class="notification is-danger">
{{ error }}
</div>
{% endfor %}
{% endif %}
<div class="field">
<label>Content</label>
<div class="control">
<textarea class="textarea" name="content" id="id_content"></textarea>
</div>
</div>
<div class="field">
<label>Experience</label>
<div class="control">
<textarea class="textarea" name="experience" id="id_experience"></textarea>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-success">Submit</button>
</div>
</div>
</form>
{% endblock %}
what could be wrong with my code?
the error in this line
<form method="post" action=".">
just delete the point, and it should work,
<form method="post" action="">
I have been trying to learn Django.
I am stuck on this form part. A form has been created that allows the user to create an Album object where they can fill in the Artist, Album Name, Genre and upload an Album Logo. When I fill in the fields and then click submit, it should then redirect me to the details page for that particular Album that just got created. But nothing appears to happen when clicking the submit button and the object does not get created.
Here is the models.py code that contains an Album class with 4 fields; artist, album_name, genre and album_logo.
from django.db import models
from django.urls import reverse
# Create your models here.
class Album(models.Model):
artist = models.CharField(max_length=250)
album_name = models.CharField(max_length=500)
genre = models.CharField(max_length=100)
album_logo = models.ImageField()
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk':self.pk})
def __str__(self):
return self.album_name + " - " + self.artist
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=100)
song_title = models.CharField(max_length=250)
is_favourite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
Here is the album_form.html code which contains the actual form. I have not used crispy_forms as I am not familiar with Bootstrap though I know CSS.
{% extends 'music/base.html' %}
{% block title %}Add a New Album{% endblock %}
{% block body %}
<form class="formContainer" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
{% if field.label != 'Album logo' %}
<label for="field{{ forloop.counter }}">{{ field.label }}</label>
<input type="text" id="field{{ forloop.counter }}" name="" value="">
{% else %}
<label for="field{{ forloop.counter }}">{{ field.label }}</label>
<input type="file" id="field{{ forloop.counter }}" name="" value="" accept="image/*">
{% endif %}
<br>
{% endfor %}
<input type="submit" id="submitBtn" name="" value="Add">
</form>
{% endblock %}
This is views.py code where I have made use of class based views and not function based views.
from django.views import generic
from .models import Album, Song
# Create your views here.
class IndexView(generic.ListView):
template_name = 'music/index.html'
queryset = Album.objects.all()
context_object_name = 'all_albums'
class DetailView(generic.DetailView):
model = Album
template_name = 'music/detail.html'
class AlbumCreate(generic.CreateView):
model = Album
fields = ['artist', 'album_name', 'genre', 'album_logo']
def form_valid(self, form):
return super().form_valid(form)
and finally this is my urls.py code:
from django.urls import path, include
from . import views
app_name='music'
urlpatterns = [
#/music/
path('', views.IndexView.as_view(), name='index'),
#/music/5/
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
#/music/album/add/
path('album/add/', views.AlbumCreate.as_view(), name='album-add')
]
After clicking the submit button in the form, it should take me to the "detail" url for the primary key of the Album that got created. Am I missing something here?
In your views.py you need to override the get_success_url function in your CreateView and pass the id as an argument while redirecting.
class AlbumCreate(generic.CreateView):
model = Album
fields = ['artist', 'album_name', 'genre', 'album_logo']
def form_valid(self, form):
return super().form_valid(form)
def get_success_url(self):
return reverse('music:detail', args=(self.object.id,))
Seems you forgot to put action to your <form> tag
Try this
<form class="formContainer" action='{% url 'music:album-add'%}' method="post" enctype="multipart/form-data">
Edit: Also add success url using get_success_url function in your AlbumCreate view to redirect user to album detail page, like was mentioned in above answer
from django.urls import reverse_lazy
...
class AlbumCreate(generic.CreateView):
...
def get_success_url(self, **kwargs):
return reverse_lazy('music:detail', args = (self.object.id,))
How to I bind User fields data and user profile data to a model form on my view, I only get user data rendered to a form when i use instance=user but it doesn't render any data of user profile on instance=profile, what i need is to render all user and its profile to a form.
models.py
class User(AbstractUser):
is_supervisor = models.BooleanField(default=False)
is_student = models.BooleanField(default=False)
class Supervisor(models.Model):
user = models.OneToOneField('User', on_delete=models.CASCADE, primary_key=True, related_name='supervisor')
su_mobile_number = models.CharField(max_length=200)
view.py
def supervisor_update(request, user_id):
# user = get_object_or_404(User, pk=user_id)
user = get_object_or_404(User, pk=user_id)
profile = get_object_or_404(Supervisor, pk=user_id)
if request.method == 'POST':
form = SupervisorSignUpForm(request.POST, instance=user)
else:
form = SupervisorSignUpForm(instance=user)
return save_user_form(request, form, 'partials/partial_supervisor_update.html')
form.py
class SupervisorSignUpForm(UserCreationForm):
su_mobile_number = forms.CharField(label="Mobile Number")
class Meta(UserCreationForm.Meta):
model = User
fields = ('username', 'email', 'password1', 'password2', 'first_name', 'last_name')
supervisor_update.html
{% load crispy_forms_tags %}
<form method="post" action="{% url 'supervisor_update' form.instance.pk %}" class="js-supervisor-update-form">
{% csrf_token %}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Update Supervisor</h4>
</div>
<div class="modal-body">
{% include 'partials/form_messages.html' %}
{{ form.username|as_crispy_field }}
{{ form.email|as_crispy_field }}
{{ form.first_name|as_crispy_field }}
{{ form.last_name|as_crispy_field }}
{{ form.su_mobile_number|as_crispy_field }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Update Supervisor</button>
</div>
</form>
To set the extra field passing in initial along with the user instance should work
initial = {'su_mobile_number': profile.su_mobile_number}
form = SupervisorSignUpForm(instance=user, initial=initial)
Or if you dont want to manually create the dict you could use model_to_dict
from django.forms.models import model_to_dict
initial = model_to_dict(profile, exclude=['user'])
form = SupervisorSignUpForm(instance=user, initial=initial)
Also at the top of your view you are assuming user and supervisor have the same id which could not be the case instead you could do something like this
user = user = get_object_or_404(User, pk=user_id)
profile = user.supervisor
if not profile:
raise Http404