NOT NULL constraint failed: spring_post.publisher_id - python

I created a class base create view.When i try to submite the post model create view. it will return
NOT NULL constraint failed: spring_post.publisher_id
how can i set the publisher the get the current logged in user and set it to the post piblisher field.
im a beginner
this is the publisher field in my post model
publisher=models.ForeignKey(User,on_delete=models.PROTECT)
#and this is my views
class PostCreateView(LoginRequiredMixin,CreateView):
model=Post
fields=['title','description']
redirect_field_name="login"

You need to set the .publisher of the post, so:
class PostCreateView(LoginRequiredMixin,CreateView):
model=Post
fields = ['title','description']
redirect_field_name = 'login'
def form_valid(self, form):
form.instance.publisher = self.request.user
return super().form_valid(form)
You probably should also specify the success_url [Django-doc] to specify where to redirect to if the POST request was successful.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Related

Django - Add entry to ManyToMany field through class based view

I want to add / remove members from a Team model. Members are specified as a ManyToManyField. I use django-rules to specify permissions, so team owners should be able to add/remove members.
# models.py
from django.db import models
from rules.contrib.models import RulesModel
from django.conf import settings
class Team(RulesModel):
name = models.CharField(max_length=80)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
help_text="Owner can view, change or delete this team.",
related_name="team_owner",
)
members = models.ManyToManyField(
settings.AUTH_USER_MODEL, blank=True, related_name="team_members"
)
The permissions are specified as following:
import rules
#rules.predicate
def is_team_owner(user, obj):
return obj.owner == user
rules.add_perm("teamapp.change_team", is_team_owner)
I've specified some generic views (CreateView, DetailView, UpdateView and DeleteView) to manage the Team. Now I want two separate views to add and remove members on the same.
# views.py
from django.views.generic import (
CreateView,
DetailView,
UpdateView,
ListView,
DeleteView,
)
from rules.contrib.views import PermissionRequiredMixin
from django.contrib.auth import get_user_model
from .models import Team
class TeamMemberAddView(PermissionRequiredMixin, UpdateView):
model = Team
permission_required = "teamapp.change_team"
raise_exception = True
fields = ["members"]
def form_valid(self, form):
user = get_user_model()
new_member = user.objects.get(pk=1)
self.object.members.add(new_member)
return super(TeamMemberAddView, self).form_valid(form)
Which generic view can I use to add / remove members? Which approach is recommended here? I wanted 1 dedicated view to select an existing User to be added, and some links on the list view to delete members. My approach fails, because it does not add members, it only updates to the last User selected. So the ManyToMany table only contains one record.
TL;DR: replace the last line of form_valid by return HttpResponseRedirect(self.get_success_url())
It's important to understand how form_valid of UpdateView works. I recommend to visualize the methods on ccbv.co.uk.
From ModelFormMixin:
If the form is valid, save the associated model.
def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
return super().form_valid(form)
It means that the object will be saved with the data submitted by the form. UpdateView will restrict the changes to the fields variable:
fields = ["members"]
From FormMixin:
If the form is valid, redirect to the supplied URL.
def form_valid(self, form):
"""If the form is valid, redirect to the supplied URL."""
return HttpResponseRedirect(self.get_success_url())
For your concrete case (add a many-to-many relationship), you need to bypass the model saving from ModelFormMixin by simply returning the supplied URL after adding the relationship (last line changed):
def form_valid(self, form):
user = get_user_model()
new_member = user.objects.get(pk=1)
self.object.members.add(new_member)
return HttpResponseRedirect(self.get_success_url())
Side note: your form seems to provide the member object you want to add, so you could use this instead of including it in the url. Try:
def form_valid(self, form):
for member in form.cleaned_data['members'].all():
self.object.members.add(member.id)
return HttpResponseRedirect(self.get_success_url())

How do I check if a Django user exists in a many-to-many field?

I have a Device model that has a many-to-many relationship to the built-in User object of Django. I'd like to override get_queryset() so that it only returns Device objects associated with the logged-in user.
models.py:
class Device(models.Model):
maintainers = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name="devices",
)
admin.py:
class DeviceAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super().get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(maintainers=request.user)
However, this code still shows all Device objects in my views defined in views.py, even if it is not associated with the logged-in user.
I've also tried maintainers__contains=request.user but the problem persists. What am I doing wrong? How do I correctly filter the QuerySet?
I mistakenly thought that get_queryset() would apply to all views within the Django application, including views defined in views.py. However overriding get_queryset() in admin.py only changes the view for the admin dashboard/console.
In this case, qs.filter(maintainers=request.user) correctly filters the device list in the admin console (if the user is a staff member and is allowed to access the admin console).
For anyone wishing to filter the model in views.py, add the following to your views.py file:
class DeviceView(LoginRequiredMixin, ListView):
# ...
def get_queryset(self):
return Device.objects.filter(maintainers=self.request.user)

Display a different default value in Django CreateView according to current logged in user?

Long story short, I am creating a ModelForm which will be passed to a generic CreateView. This form will allow a user to post an event with a location. I have already collected the user's base address in my user creation form, and my Event model has a foreignkey to the author of the event.
I would like to display the city and state of the currently logged in user as a default value on the event creation form. Since default values are set at the model level, I am not able to use the requests framework. Solution such as this one offer a way to save info from the request to the database upon submission but I would like to display this default when the user first navigates to the form page. How do I achieve this functionality?
Edit I would like to be able to pass an initial parameter as in this post but have it dynamically determined by the current logged in user.
Here is the essential part of the model. Note that BusinessUser has city and state fields.
class Job(models.Model):
author = models.ForeignKey(BusinessUser, on_delete = models.CASCADE)
location = models.CharField(max_length=200, blank=True, help_text="If different from the location listed on your company profile.")
And here is the view so far:
class JobCreation(LoginRequiredMixin, SuccessMessageMixin, generic.edit.CreateView):
model = Job
form_class = JobCreationForm
context_object_name = 'job'
success_url = reverse_lazy('jobs:business_profile')
success_message = 'New job posted!'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
JobCreationForm is the work in progress that I'm stuck on. At the moment, it's a ModelForm giving the model and fields.
class JobCreationForm(ModelForm):
class Meta:
model = Job
fields = (
'job_title',
'location',
)
You can override get_initial if you want to set initial data dynamically. If you don't need to set it dynamically you can simply set initial.
class JobCreation(LoginRequiredMixin, SuccessMessageMixin, generic.edit.CreateView):
model = Job
form_class = JobCreationForm
def get_initial(self):
initial = super().get_initial()
initial['location'] = self.request.user.location
return initial
...

I would like to add condition to Django DetailView

I am using Django Generic view, DetailView.
But I'd like to block users to access to detail post who did not email_confirmed yet.
I have a email_confirmed field in User model.
My code is :
#method_decorator(login_required(login_url='/login/'), name='dispatch')
class RecruitView(generic.DetailView):
model = Recruit
template_name = 'recruit.html'
and I want to add :
if not request.user.email_confirmed:
error_message = "you did not confirmed yet. please check your email."
return render(request, 'info.html', {'error_message': error_message})
else: pass
How can I add this condition to DetailView?
(I tried to override 'as_view' but I don't know how to do it)
I would use the PermissionRequiredMixin. With this you can specify specific permissions users need to have or override the has_permission method.
from django.contrib.auth.mixins import PermissionRequiredMixin
class RecruitView(PermissionRequiredMixin, generic.DetailView):
...
login_url = '/login/'
permission_denied_message = 'you did not confirmed yet. please check your email.'
def has_permission(self):
return self.request.user.email_confirmed
This will redirect users without the email_confirmed to the login_url where you can display the error message. In order to use the index.html template instead you might need to override the handle_no_permission method.

Updating User Password in Django with Class Based Views

I'm tring write a view to administrator update a password of another user, using Class Based Views and model SetPasswordForm of Django.
My views.py
class UserSetPasswordUpdateView(GroupRequiredMixin, FormView):
form_class = forms.SetPasswordForm
model = User
template_name = 'app/admin/object_update.html'
success_url = reverse_lazy('portal:admin_user')
group_required = u"Administrator"
def get_form_kwargs(self):
kwargs = super(UserSetPasswordUpdateView, self).get_form_kwargs()
kwargs['user'] = User.objects.filter(pk=self.kwargs['pk'])
return kwargs
update_change_password = UserSetPasswordUpdateView.as_view()
My urls.py
url(r'^app/admin/update-user-pass/(?P<pk>[0-9]+)$', update_views.update_change_password, name='update_change_password'),
And don't show any errors, just go to success_url, but the password don't updated.
Your view is based on FormView. This doesn't have any knowledge of model forms, and doesn't do anything with the data other than check that it is valid. SetPasswordForm changes the password when the form is saved, but this view never does this.
You could override form_valid to call form.save() explicitly, but it would be better to use a more appropriate base class such as UpdateView which will do that for you.

Categories