I am using django forms to add a new object(page) to the db and after submitting the form i want to redirect to the url of page detail but the problem is that i didn't have the id of the page that is being created.
I'm new to django so please help me in this.
model.py file
class UserPage(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
cover_page = models.FileField()
page_name = models.CharField(max_length=250)
forms.py
from django import forms
from .models import UserPage
class PageForm(forms.ModelForm):
class Meta:
model = UserPage
exclude = ['user']
fields = [
"page_name",
"cover_page"
]
view.py
def create(request):
if request.user.is_authenticated():
if request.method=='POST':
form = PageForm(request.POST , request.FILES)
if form.is_valid():
instance = form.save(commit = False)
instance.user = User.objects.get(id=request.user.id)
instance.save()
else:
form = PageForm()
context = {
"form" : form,
}
return render(request, 'pages/create.html', context)
else:
messages.error(request, "please Login First")
return HttpResponseRedirect(reverse('index'))
url.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<page_id>[0-9]+)/$', views.pageDetail, name='pagedetail'),
url(r'^create/$', views.create, name='create_check'),
]
Yes, you do have that id: in instance.
instance.save()
return redirect('pagedetail', page_id=instance.id)
Related
Main problem:
When user is at this url http://127.0.0.1:8000/8/, so group_id is already in url of his current page, he must choose group_id that he wants to assign task, if I do fields = ['title', completed'] in forms.py user can't choose group_id but he needs to. I have primary key but I don't know where to apply it in views
P.S.:
IndexView from views.py has no problem in it and works fine, also get method in GroupView works fine to. Anything works fine but user needs to choose a group that he want's to assign tasks
forms.py:
from django import forms
from .models import *
class AddTaskForm(forms.ModelForm):
class Meta:
model = Task
fields = '__all__'
class AddGroupForm(forms.ModelForm):
class Meta:
model = Group
fields = '__all__'
models.py
from django.db import models
from django.utils import timezone
class Group(models.Model):
title = models.CharField(max_length=255)
def __str__(self):
return self.title
class Task(models.Model):
title = models.CharField(max_length=255)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
views.py
from django.shortcuts import render, redirect
from django.views import generic
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from .models import *
from .forms import *
class IndexView(generic.ListView):
template_name = 'tasks/index.html'
form_class = AddGroupForm
model = Group
def get_queryset(self):
return self.groups.order_by('title')
def get(self, request):
self.groups = Group.objects.all().order_by('title')
form = self.form_class(request.GET)
return render(request, self.template_name, {'form': form, 'groups': self.groups})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
form.save()
return redirect('/')
return render(request, self.template_name, {'form': form, 'groups': self.groups})
class GroupView(generic.ListView):
template_name = 'tasks/group.html'
form_class = AddTaskForm
model = Task
def get_queryset(self):
return self.tasks.order_by('-completed', 'title')
def get(self, request, pk):
self.group_id = pk
self.tasks = Group.objects.get(pk=pk).task_set.all()
form = self.form_class(request.GET, pk)
return render(request, self.template_name, {'form': form, 'tasks': self.tasks})
def post(self, request, pk):
form = self.form_class(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.group_id = pk
form.save()
return HttpResponseRedirect(reverse('tasks:group', args=[pk]))
urls.py
from django.urls import path
from . import views
app_name = 'tasks'
urlpatterns = [
path('', views.IndexView.as_view(), name = 'index'),
path('<str:pk>/', views.GroupView.as_view(), name = 'group'),
]
Once you have the id in the url, you may use it in the form valid method. This is the place to add information befor writing to the DB:
def form_valid(self, form):
form.instance.group= Group.objects.get(pk=self.kwargs['pk'])
return super().form_valid(form)
By the way: Your url might be <int:pk> (not str) as automated generated pks are integer. And you may provide a better name for your parameter. Like <int:group_pk>
This makes your code more readable: self.kwargs['group_pk']
I want to create a PostModel(just like instagram) and while the form is created to connect the user to the model with One-to-one/foreign key relationship, anyway I'm getting a problem while trying to upload an image and the db doesn't updates.
I've tried this solution
...
# models.py
from django.contrib.auth.models import User
from django.conf import settings
class Post(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
description = models.CharField(max_length=255, blank=True)
image = models.ImageField(upload_to='images')
uploaded_at = models.DateTimeField(auto_now_add=True)
...
# forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('description', 'image', )
def save(self, commit=True):
if commit:
Post.save()
return Post
...
# views.py
def account(request):
post = PostForm(request.POST, request.FILES)
if request.method == "POST":
if post.is_valid():
post.save(commit=False)
post.owner = request.user
post.save(commit=True)
messages.success(request, f"you had successfully updated your profile image")
return redirect("main:account")
else:
for msg in form.error_messages:
messages.error(request, f"{msg}: {form.error_messages[msg]}")
return render(request = request,
template_name = "main/account.html",
context={'PostForm':post})
post = PostForm()
return render(request = request,
template_name = "main/account.html",
context={'PostForm':post})
You should not override the def save() method, this is fine as it is now, so:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('description', 'image', )
# no save
as for the view, you need to add the owner to the object, but here you are adding it to the form, and that thus has no effect (on the object):
from django.contrib.auth.decorators import login_required
#login_required
def account(request):
post = PostForm(request.POST, request.FILES)
if request.method == 'POST':
if post.is_valid():
post.instance.owner = request.user
post.save()
messages.success(request, f'you had successfully updated your profile image')
return redirect('main:account')
# …
I would also advise to rename post to post_form, since this is a form, not a post object.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
I am new to django, I migrated my models, the database is working fine, i can see the data that I added by the manage.py shell. But I cant add Data from my webApp. When I wrote text on the fields and press the submit button it gave me this error NOT NULL constraint failed: sms_post.author_id
Thanks for helping..
models.py files
from django.db import models
from django.contrib.auth.models import User
THE_GENDER = [
("Monsieur", "Monsieur"),
("Madame", "Madame")
]
class Post(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
gender = models.CharField(max_length=8, choices=THE_GENDER)
number = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
forms.py files
from django import forms
from .models import Post
from crispy_forms.helper import FormHelper
class post_form(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(post_form, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
class Meta:
model = Post
fields = ["name", "email", "gender", "number"]
views.py files
from django.shortcuts import render
from django.http import HttpResponse
from .forms import post_form
from django.contrib.auth.decorators import login_required
#login_required
def home(request):
form = post_form(request.POST or None)
if form.is_valid():
form.save()
context = {
"form": form
}
return render(request, "sms/home.html", context)
You did not set the author of the instance in your for to a User object. You can do this with:
from django.shortcuts import redirect
#login_required
def home(request):
if request.method == 'POST':
form = post_form(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
return redirect('name-of-view')
else:
form = post_form()
context = {
'form': form
}
return render(request, 'sms/home.html', context)
In order to implement the Post/Redirect/Get pattern [wiki], in case of a successful POST request, you should make a redirect, for example to the same view. You thus can here replace 'name-of-view' with the name of a view to redirect to.
Error Image
When i'm trying to add Url of candidate_slug i'm getting an error about:
Unknown field(s) (category_slug) specified for Candidate. Check fields/fieldsets/exclude attributes of class CandidateAdmin
on add a candidate button
and when i remove urls from admin i cannot add categories over my series and i'm unable to go to series after the category that shows on the homepage
urls.py
from django.urls import path, include
from . import views
app_name = 'main'
urlpatterns = [
path("", views.homepage, name="homepage"),
path("signup/", views.signup, name="signup"),
path("login/", views.login_request, name="login"),
path("logout", views.logout_request, name="logout"),
path("profile/", views.profile, name="profile"),
path("account/", views.account, name="account"),
path("<single_slug>", views.single_slug, name="single_slug"),
]
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .models import Candidate, CandidateCategory, CandidateSeries
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login, logout, authenticate
from django.contrib import messages
from .forms import NewUserForm
# Code for Showing(rendering) Homepage
def homepage(request):
return render(request=request,
template_name="main/categories.html",
context={'categories': CandidateCategory.objects.all})
# Code for showing profiles section
def profile(request):
return render(request,
"main/profile.html",
)
def single_slug(request, single_slug):
categories = [c.category_slug for c in CandidateCategory.objects.all()]
if single_slug in categories:
matching_series = CandidateSeries.objects.filter(candidate_category__category_slug=single_slug)
series_urls = {}
for m in matching_series.all():
part_one = Candidate.objects.filter(candidate_series__candidate_series=m.candidate_series).earliest("candidate_published")
series_urls[m] = part_one.candidate_slug
return render(request=request,
template_name='main/category.html',
context={"candidate_series": matching_series, "part_ones": series_urls})
categories = [ca.candidate_slug for ca in Candidate.objects.all()]
if single_slug in categories:
this_candidate = Candidate.objects.get(candidate_slug=single_slug)
candidates_from_series = Candidate.objects.filter(candidate_series__candidate_series=this_candidate.candidate_series).order_by('candidate_published')
this_candidate_idx = list(candidates_from_series).index(this_candidate)
return render(request,
"main/candidate.html",
{'candidates': this_candidate,
'sidebar': candidates_from_series,
'this_cat_idx': this_candidate_idx})
# Code for account
def account(request):
return render(request,
"main/account.html",
)
# Code for Signing up for a new account
# this code also checks it the user already exists then it will throw the user already exists popup error message
def signup(request):
if request.method == "POST":
form = NewUserForm(request.POST)
if form.is_valid():
user = form.save()
username = form.cleaned_data.get('username')
messages.success(request, f"New account created: {username}")
login(request, user)
return redirect("main:homepage")
else:
for msg in form.error_messages:
messages.error(request, f"{msg}: {form.error_messages[msg]}")
return render(request,
"main/signup.html",
{'form': form})
form = NewUserForm
return render(request=request,
template_name="main/signup.html",
context={'form': form})
# Code for Logging in a user
# it also authenticates if this user is valid or invalid
def login_request(request):
if request.method == "POST":
form = AuthenticationForm(request=request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
messages.info(request, f"You are now Logged in as {username}")
return redirect('/')
else:
messages.error(request, f"Invalid Username of Password")
else:
messages.error(request, f"Invalid Username of Password")
return render(request,
"main/login.html",
{'form': form})
form = AuthenticationForm
return render(request,
"main/login.html",
{'form': form})
# This code is simply for logging out a user
def logout_request(request):
logout(request)
messages.info(request, f"User Logged out Successfully!!!")
return redirect("main:homepage")
admin.py
from django.contrib import admin
from .models import Candidate, CandidateSeries, CandidateCategory
from django.db import models
from tinymce.widgets import TinyMCE
class CandidateAdmin(admin.ModelAdmin):
fieldsets = [
("Title/date", {'fields': ["candidate_name", "candidate_published"]}),
("URL", {'fields': ["category_slug"]}),
("Series", {'fields': ["candidate_series"]}),
("Content", {'fields': ["candidate_content"]}),
]
formfield_overrides = {
models.TextField: {'widget': TinyMCE()},
}
admin.site.register(CandidateSeries)
admin.site.register(CandidateCategory)
admin.site.register(Candidate, CandidateAdmin)
models.py
from django.db import models
from datetime import datetime
class CandidateCategory(models.Model):
candidate_category = models.CharField(max_length=200)
category_summary = models.CharField(max_length=200)
category_slug = models.CharField(max_length=200, default=1)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.candidate_category
class CandidateSeries(models.Model):
candidate_series = models.CharField(max_length=200)
candidate_category = models.ForeignKey(CandidateCategory, default=1, verbose_name="Category", on_delete=models.SET_DEFAULT)
series_summary = models.CharField(max_length=200)
class Meta:
verbose_name_plural = "Series"
def __str__(self):
return self.candidate_series
class Candidate(models.Model):
candidate_name = models.CharField(max_length=200)
candidate_content = models.TextField()
candidate_published = models.DateTimeField('date published', default=datetime.now())
candidate_series = models.ForeignKey(CandidateSeries, default=1, verbose_name="Series", on_delete=models.SET_DEFAULT)
candidate_slug = models.CharField(max_length=200, default=1)
def __str__(self):
return self.candidate_name
You have the following entry in CandidateAdmin.fieldsets
("URL", {'fields': ["category_slug"]}),
The Candidate model does not have a field category_slug, this is probably supposed to be
("URL", {'fields': ["candidate_slug"]}),
I am new to Django.I want to create app that would enable selected users to login and then upload files that would latter be processed.
models.py
class Profile(models.Model):
username = models.OneToOneField(User, on_delete=models.CASCADE)
password = models.TextField(max_length=80,blank=True)
company = models.TextField(max_length=80, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
class Document(models.Model):
uploaded_by = models.ForeignKey(Profile,on_delete=models.CASCADE)
date_uploaded = models.DateTimeField(auto_now_add=True)
forms.py
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
company = forms.CharField()
class DocumentForm(forms.Form):
docfile = forms.FileField(label='Select a file')
malex.urls(application urls)
from malex.views import list
from malex.views import login
urlpatterns = [
url(r'^list/$', list, name='list'),
url(r'^login/$', login, name='login'),
]
project/urls
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^newp/', include('malex.urls')),
]
views.py
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
user = authenticate(user=cd['user'],password=cd['password'],company=cd['company'])
if user is not None:
if user is active:
login(request,user)
return HttpResponse('Authenticated successfully')
else:
return HttpResponse('Disabled account')
else:
return HttpResponse('Invalid login')
else:
form=LoginForm()
return render(request,'account/login.html',{'form': form})
def list(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile=request.FILES['docfile'])
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('list'))
Now the login and upload operations are separated.
How to change my views and urls to have login first and upload latter?
Do I need to use Class based views with decorators?
create a custom login form and view.
use your localhost:8000 address as login template
(app) urlpatterns = [path('',views.loginview,name = 'login')]
(project) urlpatterns = [path('', include('malex.urls')),)]
extend your login template using {% block content %}{% endblock %}
use pass restrictions {% if request.user.is_authenticated %} in template or view to let them access upload section.