Consider the FormView that I'm overriding, below. Upon successful creation of a new League record, how do I reference that record so that I can redirect the user to a more general edit page specific to that League?
class LeagueView(FormView):
template_name = 'leagueapp/addleague.html'
form_class = LeagueForm
def form_valid():
newleague = ??? #newly created league
success_url = '/league/editleague/' + str(newleague.id)
return HttpResponseRedirect(self.get_success_url())
this is really straight forward, given an url in the league namespace like
url(r'^league/editleague/(?P<id>\d+>)$', LeagueView.as_view(), name='edit')
you should edit the form_valid method in this way:
from django.shortcuts import redirect
class LeagueView(FormView):
template_name = 'leagueapp/addleague.html'
form_class = LeagueForm
def form_valid(self, form):
newleague = form.save()
return redirect('league:edit', id=newleague.id)
Related
My code is:
views.py
class supplierListView(LoginRequiredMixin, ListView):
template_name = "supplier/Supplier_list.html"
def get_queryset(self):
organisation = self.request.user.userprofile.company
return Supplier.objects.filter(organisation=organisation)
class supplierCreateView(LoginRequiredMixin, CreateView):
template_name = "supplier/supplier_create.html"
form_class = SupplierModelForm
def get_success_url(self):
return reverse("supplier:supplier_list")
def form_valid(self, form):
supplier = form.save(commit=False)
supplier.organisation = self.request.user.userprofile.company
supplier.supplier_created_by = self.request.user
supplier.save()
my urls:
from awesomeinventory.supplier.views import (
supplierListView,
supplierDetailView,
supplierCreateView,
supplierContactListView,
supplierContactCreateView,
supplierContactDetailView,
)
app_name = "supplier"
urlpatterns = [
path("supplier_list/", view=supplierListView.as_view(), name="supplier_list"),
path("supplier_create/", view=supplierCreateView.as_view(), name="supplier_create"),
path("<int:pk>/detail/", view=supplierDetailView.as_view(), name="supplier_detail"),
path("<int:pk>/update/", view=supplierDetailView.as_view(), name="supplier_update"),
path("<int:pk>/delete/", view=supplierDetailView.as_view(), name="supplier_delete"),
path("supplierContact_list/", view=supplierContactListView.as_view(), name="supplierContact_list"),
path("<int:suppk>/supplierContact_create/", view=supplierContactCreateView.as_view(), name="supplierContact_create"), # int is supplier_id
path("<int:pk>/Contact/detail/", view=supplierContactDetailView.as_view(), name="supplierContact_detail"),
]
I m able to go to supplier:supplier_list page and it works well.
But when I want to create a supplier with supplierCreateView, supplier is create but it seems to have an issue with get_success_url as I have error
The view awesomeinventory.supplier.views.supplierCreateView didn't return an HttpResponse object. It returned None instead
The method form_valid is supposed to return the response or redirect the user. In your implementation you only save the object and return nothing essentially returning None which gives you an error. Instead of using form.save(commit=False) you can simply modify the instance wrapped by the form and leave all the processing to the super classes form_valid:
class supplierCreateView(LoginRequiredMixin, CreateView):
template_name = "supplier/supplier_create.html"
form_class = SupplierModelForm
def get_success_url(self):
return reverse("supplier:supplier_list")
def form_valid(self, form):
form.instance.organisation = self.request.user.userprofile.company
form.instance.supplier_created_by = self.request.user
return super().form_valid(form)
Note: A class name should ideally be in PascalCase so SupplierCreateView instead of supplierCreateView
This will work for you.
from django.urls import reverse_lazy
class supplierCreateView(LoginRequiredMixin, CreateView):
template_name = "supplier/supplier_create.html"
form_class = SupplierModelForm
def get_success_url(self):
# pay attention I'm using reverse_lazy instead of reverse
return reverse_lazy("supplier:supplier_list")
You can read more about reverse_lazy here.
Im searching for a way to check user groups when request User is in the same group as the Creator then access and when not then access declined.
The reason behind this is that not every Staff Member may edit all contributions. Only if the staff member is in the same group as the author, then the staff member may edit the article.
My View:
class EditArticleView(LoginRequiredMixin, UpdateView):
model = Article
message = _("Your Article has been updated.")
form_class = ArticleForm
template_name = 'articles/article_update.html'
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
def get_success_url(self):
messages.success(self.request, self.message)
return reverse('articles:list')
'''
def get_queryset(self):
queryset = super(EditArticleView, self).get_queryset()
queryset = queryset.filter(user=self.request.user)
print(self.request.user)
return queryset
'''
As an alternative you might also consider using the UserPassesTest mixing as described in the docs:
from django.contrib.auth.mixins import UserPassesTestMixin
class EditArticleView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
def test_func(self):
article = self.model.objects.get(pk=self.kwargs['pk'])
return Group.objects.filter(user=self.request.user).filter(user=article.author).exists() # Or any other test you need
# ... Your other view code
class Event(models.Model):
...
class Question(models.Model):
event = models.ForeignKey(Event)
And I have url pattern like /events/(?P<event_id>\d+)/question/add/$ bound to QuestionCreateView
QuestionCreateView(CreateView):
model = Question
form_class = QuestionForm
def form_valid(self, form):
form.instance.event = [???]
return super(QuestionCreateView, self).form_valid(form)
What I'd like to get:
throw a 404 error if user requests invalid event_id like /events/9999999/objects/add/
get an Event instance from url's event_id and populate my new Question instance before saving
do it in a DRY way, since I have some other models with relations like this
Is it possible with class-based views? It looks like some crazy mix of DetailView for Event and CreateView for Question.
Url keyword arguments are available in the view as self.kwargs:
from django.shortcuts import get_object_or_404
class QuestionCreateView(CreateView):
model = Question
form_class = QuestionForm
def form_valid(self, form):
form.instance.event = get_object_or_404(Event,
pk=self.kwargs['event_id'])
return super(QuestionCreateView, self).form_valid(form)
I have two, presumably related, problems with UpdateView. First, it is not updating the user but creating a new user object. Second, I cannot restrict the fields displayed in the form.
Here is my views.py:
class RegistrationView(FormView):
form_class = RegistrationForm
template_name = "register.html"
success_url = "/accounts/profile/"
def form_valid(self, form):
if form.is_valid:
user = form.save()
user = authenticate(username=user.username, password=form.cleaned_data['password1'])
login(self.request, user)
return super(RegistrationView, self).form_valid(form) #I still have no idea what this is
class UserUpdate(UpdateView):
model = User
form_class = RegistrationForm
fields = ['username', 'first_name']
template_name = "update.html"
success_url = "/accounts/profile/"
and urls.py
url(r'^create/$', RegistrationView.as_view(), name="create-user"),
url(r'^profile/(?P<pk>\d+)/edit/$', UserUpdate.as_view(), name="user-update"),
How do I properly use UpdateView?
Problem 1.
The user is not being updated because you are using the same form
(RegistrationForm) to do your updates and to create new users.
Problem 2. Forms belong in a file of their own called forms.py.
My suggested refactoring:
#forms.py
#place(forms.py) this in the same directory as views.py
class UpdateForm(forms.ModelForm):
#form for updating users
#the field you want to use should already be defined in the model
#so no need to add them here again DRY
class Meta:
model = User
fields = ('field1', 'field2', 'field3',)
#views.py
#import your forms
from .forms import UpdateForm
#also import your CBVs
from django.views.generic import UpdateView
class UserUpdate(UpdateView):
context_object_name = 'variable_used_in `update.html`'
form_class = UpdateForm
template_name = 'update.html'
success_url = 'success_url'
#get object
def get_object(self, queryset=None):
return self.request.user
#override form_valid method
def form_valid(self, form):
#save cleaned post data
clean = form.cleaned_data
context = {}
self.object = context.save(clean)
return super(UserUpdate, self).form_valid(form)
slightly elegant urls.py
#urls.py
#i'm assuming login is required to perform edit function
#in that case, we don't need to pass the 'id' in the url.
#we can just get the user instance
url(
regex=r'^profile/edit$',
view= UserUpdate.as_view(),
name='user-update'
),
You left out a lot of info so not really sure what your setup is.My solution is based on the assumption that you have Django 1.5. You can learn more about handling forms with CBVs
first: user = form.save() saves in the db the form. since there's no pk in the form it creates a new one.
what you have to do is probably to check if a user with that username exists and if not create it (for this part check google).
second: to restrict field you have to specify them in the Meta class of the Form (which you didn't show here) check this https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#modelform.
If you are getting new objects in the database instead of updating existing ones then it is likely that you copied and pasted the template for new objects and forgot to change the form's action attribute. This should point to view that does the update either in the form of a hard-coded path or a URL tag ({% url '<name of URLconf>' object.id %).
I have the following view which extends the base CreateView:
class PeopleImportCsv(FailedLoginMessageMixin, CreateView):
model = CsvFile
form_class = CustomerCsvImportForm
template_name = 'people/customer_uploadcsv_form.html'
def get_success_url(self):
url = reverse('customer_process_csv', args=[self.object.id])
return url
def form_valid(self, form):
instance = form.save(commit=False)
instance.uploaded_by = self.request.user
super(PeopleImportCsv, self).form_valid(form)
I am using the get_success_url() method so I can get the id of the newly created object in the database. However, when I attempt to submit my form I get the following ValueError message:
The view people.views.PeopleImportCsv didn't return an HttpResponse object.
If I place an assert False immediately after assigning the url in get_success_url() then I can see that it has the correct url I'm expecting so what can I do to sort this out?
You need to have a return from the form_valid method (if you are using a ModelForm):
def form_valid(self, form):
instance = form.save(commit=False)
instance.uploaded_by = self.request.user
return super(PeopleImportCsv, self).form_valid(form)
You can see the methods signature in the Django source
P.S There is a very useful site for referencing Djangos many class based views here: http://ccbv.co.uk/