I have created a functional Django (1.11.5) system which allows me to add numerous Bikes to Manufacturer due to the foreign key capabilities. Unfortunately I can't get my head around how I correctly can redirect user to (PrimaryKey) Manufacturer after the user has updated the Bike information. My views uses Class Based Views for deleting, creating, and updating both the Manufacturer and Bikes.
Below I have displayed both the views.py and URL.py I have within my App.
views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from .models import Manufacturer, Review
class ReviewUpdate(UpdateView):
model = Bike
fields = ['bike_body']
success_url = reverse_lazy('manufacturers:index')
URLs.py
url(r'bike/(?P<pk>[0-9]+)/$',views.BikeUpdate.as_view(), name="bike-update"),
What you can do is override the get_success_url method on your view.
class ReviewUpdate(UpdateView):
model = Bike
fields = ['bike_body']
def get_success_url(self):
return reverse('the-url-you-want', args=(your_key,))
More info about the recently saved object can be found at self.kwargs.
Related
I'm developing a site where I can manually add photographers to the Django adminpanel and then upload the images taken by them.
I used the default User system in Django and added a field here that shows this user is a photographer or not :
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
is_photographer = models.BooleanField(default=True)
Also, in the model that I need to put the images, I used ManyToMany field for photographers (because these photos may have been taken by several people) :
from registration import User
class Photo(models.Model):
...
photographers = models.ManyToManyField(User)
The problem is that when adding a new image to the admin panel, users who are not photographers and the is_photographer is False, is also displayed in the Photographers. I want only users who are photographers to be displayed and not normal users.
You can use Django formfield. Django has placed these formfields for different types of fields. To use formfields in ManyToMany relationships, you can use formfield_for_manytomany in the model admin_class.
Try putting this function in the Photo model admin class in the admin.py file of the application where the Photo model is located, and if you don't have a class admin, create one like this:
from .models import Photo
from django.contrib import admin
from registration.models import User
class PhotoAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
kwargs["queryset"] = User.objects.filter(is_photographer=True)
return super(PhotoAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
admin.site.register(Photo, PhotoAdmin)
In your admin.py file do this:
class PhotoAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
kwargs['queryset'] = Users.objects.filter(is_photographer=True)
return super().formfield_for_manytomany(db_field, request, **kwargs)
admin.site.register(Photo, PhotoAdmin)
You can work with the limit_choices_to=… [Django-doc]:
from django.conf import settings
class Photo(models.Model):
# …
photographers = models.ManyToManyField(
setting.AUTH_USER_MODEL,
limit_choices_to={'is_photographer': True}
)
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.
I want to turn a function view into a class-based view.
Here is the View & URL path that I have right now.
View:
def customer(request, pk):
customer = Customer.objects.get(id=pk)
return render(request, 'accounts/customer.html)
URL Path:
path('customer/<str:pk>/, views.customer, name='customer')
What would the proper syntax be to turn this view into a class-based view.
I am mainly curious about how to access the primary key here using a class-based view.
Thanks!
You can use Detail View.
in your views.py
from django.views.generic.detail import DetailView
from .models import Customer
class CustomerDetails(DetailView):
model = Customer
template_name = 'customerdetail.html' #deafaults to customer_detail.html
in urls.py
path('customer/<int:pk>', views.CustomerDetails.as_view(), name='customer')
the context that will be passed to customerdetail.html template will have the default name 'object'. access the fields of customer instance by {{object.<field_name>}}.
You can override the attributes and methods of DetailView.
for moreinfo : DetailView
If you want more control in your view you can use generic View
from django.views.generic.detail import View
from .models import Customer
class CustomerDetails(View):
def get(self, *args, **kwargs):
customer = Customer.objects.get(id=kwargs['pk'])
return render(self.request, 'accounts/customer.html)
urls.py
path('customer/<int:pk>', views.CustomerDetails.as_view(), name='customer')
arguments found in the url are stored in **kwargs
When I started to use Django, I was using FBVs ( Function Based Views ) for pretty much everything including signing up for new users.
But as I delved deep more into projects, I realized that Class-Based Views are usually better for large projects as they are more clean and maintainable but this is not to say that FBVs aren't.
Anyway, I migrated most of my whole project's views to Class-Based Views except for one that was a little confusing, the SignUpView.
In order to make SignUpView in Django, you need to utilize CreateView and SuccessMessageMixin for creating new users as well as displaying a success message that confirms the account was created successfully.
Here's the code :
views.py:
from .forms import UserRegisterForm
from django.views.generic.edit import CreateView
class SignUpView(SuccessMessageMixin, CreateView):
template_name = 'users/register.html'
success_url = reverse_lazy('login')
form_class = UserRegisterForm
success_message = "Your profile was created successfully"
and, the forms.py:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'first_name']
You can use Django's CreateView for creating a new user object.
# accounts/views.py
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views import generic
class SignUp(generic.CreateView):
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
For more info, check https://learndjango.com/tutorials/django-signup-tutorial
I want to customize Django Admin to have specific section for objects of my models (Such as Post or Product models) that use as an archive section.
I now that, I need one field in my models that shown status of objects (Such as is_archive field), but I don't have any idea about how to display them in Django Admin.
Does anyone have an opinion on this?
Create Proxy model for model you need
Create separate section in your admin panel for this proxy model
Override get_queryset() for it.
models.py
from django.db import models
class Post(models.Model):
...
is_archive = models.BooleanField(default = False)
...
class PostProxy(Post):
class Meta:
proxy = True
admin.py
from django.contrib import admin
from .models import *
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
...
#admin.register(PostProxy)
class PostProxyAdmin(admin.ModelAdmin):
...
def get_queryset(self, request):
return super().get_queryset(request).filter(is_archive=True)
Hi I am new to Django and I have created a login/logout model Django inbuilt User and UserCreationForm. It is working fine but my issue is I have define two custom inputs in my form and it is displaying on the web page when I run the server but when I check the user under the admin, I only see the details of User defined fields not my custom fields.
How to save it's data to my User model?
or maybe If I defined the custom fields wrong how do I change it so that I can save it's data in my model.
My custom defined fields that is address and phone number is not showing in Admin User and it's data is not getting saved.
model.py
from django.db import models
from django.contrib import auth
# Create your models here.
class User(auth.models.User,auth.models.PermissionsMixin):
def __str__(self):
return "#{}".format(self.username)
forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django import forms
class UserCreateform(UserCreationForm):
address = forms.CharField(max_length=150, required=True)
phone_number = forms.IntegerField(required=True)
class Meta(UserCreationForm.Meta):
model = get_user_model()
fields = ('username','email','password1','password2')
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].label = 'Display Name'
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import CreateView
from . import forms
# Create your views here.
class SignUp(CreateView):
form_class = forms.UserCreateform
success_url = reverse_lazy('login')
template_name = 'account/signup.html'
Adding fields to a ModelForm doesn't do anything in terms of saving them, if they are not fields of the Model. So of course, address and phone_number aren't saved, your User model doesn't have those fields.
You need to have a Model to save those fields. As explained here, you have two options:
Create a Profile model to save all extra fields
Create a custom User model, subclassing AbstractUser or AbstractBaseUser.
My advice: Do both. Save your extra fields in a Profile model.
And subclass AbstractUser, so you have the option to add useful methods and properties to the User model (right now, just __str__()).
Why not just subclass? Because as your app grows, you'll want to add more an more things to a user's profile. Maybe you want to create different types of profiles, e.g. the private profile and the professional profile. The User itself should be compact, just managing authentication and permissions.
Note: your current User model is wrong. You must not subclass auth.User but auth.AbstractUser.