I am building an app where managers can create a private webpage, they need to add people manually in order for them to access the page.
I don't want the managers to see all of the users, So I would like to render only the PK in the list.
My views.py
class HotelCreateView(LoginRequiredMixin, CreateView):
model = Hotel
form_class = HotelForm
def form_valid(self, form):
form.instance.manager_hotel = self.request.user
return super().form_valid(form)
forms.py
from django.db import models
from django.forms import ModelForm
from .models import Hotel
class ColleagueChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return obj.get_pk()
class HotelForm(models.Model):
ColleagueModelChoiceField(queryset=Colleague.objects.filter(pk))
You're setting fields on your CreateView, so you're letting Django generate the ModelForm automatically for you. The form uses a ModelMultipleChoiceField, which derives from ModelChoiceField, described here.
If you read the last paragraph of that section, you'll see that the display values for such a field are coming from the model's __str__ method, or you can override this with the label_from_instance() method.
That's therefore what you need to do, override this method on the ModelMultipleChoiceField. But to do that, you need to specify your own form.
So:
Create your own ModelForm for your Hotel model (HotelForm).
Create a subclass of ModelMultipleChoiceField (ColleagueChoiceField) and override the label_from_instance() method to display the pk.
Set the colleagues field on the HotelForm to be a ColleagueChoiceField.
Remove the fields attribute on your view and set the form_class to your HotelForm instead.
Related
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.
I am a beginner programming in Django framework and I am learning how to implement a CreateView (a class based view for creating a form based on a model) in my views.py file.
No, you don't the view will automatically create a model form for you, but you have to option of overwriting it.
Let's assume you have MyModel, you can do this:
from myapp.models import MyModel
# views.py
class MyCreateView(CreateView):
model = MyModel
fields = ['something', 'somethingelse'] # these are fields from MyModel
If you do not specify the fields Django will throw an error.
If you want to customize your form validation in some way, you can do this:
# forms.py
class MyForm(ModelForm):
class Meta:
model = MyModel
fields = ['something'] # form fields that map to the model
# ... do some custom stuff
# views.py
class MyCreateView(CreateView):
model = MyModel
form_class = MyForm
Notice that we are not specifying the fields anymore on MyView because if we would it will also throw an error, and the reasons is because the view will fetch the fields from the form.
More information: https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-editing/
Code that handles the form_class: https://github.com/django/django/blob/master/django/views/generic/edit.py#L74
You don't need to create a ModelForm, you just need to specify the model in the model attribute, e.g. for an Author model set model = Author.
CreateView uses the ModelFormMixin, which uses this model attribute to handle the ModelForm:
from django.views.generic.edit import CreateView
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
See more here: https://docs.djangoproject.com/en/2.1/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.model
I am using Generic Class based views for my Project like:
ListView (Queryset returning all the objects)
DetailView (Queryset for single object)
CreateView (Foreignkey data in select boxes)
UpdateView (Foreignkey data in select boxes)
How to write a generic Mixin for CBV so that the queryset returns only the data owned by the logged in user.
Just add get_queryset method and loginrequiredmixed like:
from django.contrib.auth.mixins import LoginRequiredMixin
class ArticleListView(ListView, LoginRequiredMixin):
model = Article
def get_queryset(self):
return Article.objects.filter(publisher=self.request.user) #Just and example, fit it to your problem
I have two models: Page and a custom user model MyUser
These two models have each one a manytomanyfield:
class Page(models.Model):
members = models.ManyToManyField(settings.AUTH_USER_MODEL)
class MyUser(AbstractUser):
mypages = models.ManyToManyField(Page)
objects = UserManager()
When I add a member to the members manytomanyfield via the admin interface, I would like to add the new attributed Page object to the user automatically in the mypages attribute, so I am trying to override the save method of the Page model in the admin.py:
class PageAdmin(admin.ModelAdmin):
def save_related(self, request, form, formsets, change):
super(ModelAdmin, self).save_related(request, form, formsets, change)
if 'members' in form.changed_data:
#And I am quite lost....
Is it a good idea? Should I do that in the "Page model custom save" method in my models.py file either doing it in the admin.py?
I tried to replace the #And I am quite lost.... part with ideas from:
Link1
Link2
Without any sucess!
This is completely mistaken. A many-to-many field is already double-ended. You don't need to define it on both ends. When you define a members field on Page, then MyUser will automatically get a page_set accessor which is the other end of the relation, and any page that adds a user to its members will automatically show up in the user's page_set. There is no need for any code.
Following Kevin Dias instructions in this article, I try to generate one form for two related models. This seems to work for one-to-many relations, however I run into problems using many-to-many relations.
Here is some example code for a user-role management:
#models.py
from django.db import models
class Role(models.Model): # for each role there can be multiple users
role_name=models.CharField(max_length=20)
class User(models.Model): # each user can have multiple roles
name=models.CharField(max_length=20)
role=models.ManyToManyField(Role, through='UserRole')
class UserRole(models.Model): # table to store which user has which roles
role=models.ForeignKey(Role)
user=models.ForeignKey(User)
# forms.py
from django.forms import ModelForm
from django.forms.models import inlineformset_factory
from rightmanagement.models import Role, User
class UserForm(ModelForm):
class Meta:
model = User
RoleFormSet = inlineformset_factory(User, Role) # this is probably the line that causes the problem
# views.py
from django.http import HttpResponseRedirect
from rightmanagement.models import User
from rightmanagement.forms import RoleFormSet, UserForm
# Create view
from django.views.generic import CreateView
class UserCreate(CreateView):
model = User
form_class = UserForm
def get(self, request, *args, **kwargs):
"""
Handles GET requests and instantiates blank versions of the form
and its inline formsets.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
role_form = RoleFormSet()
return self.render_to_response(
self.get_context_data(form=form,
role_form=role_form))
def post(self, request, *args, **kwargs):
"""
Handles POST requests, instantiating a form instance and its inline
formsets with the passed POST variables and then checking them for
validity.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
role_form = RoleFormSet(self.request.POST)
if (form.is_valid() and role_form.is_valid()):
return self.form_valid(form, role_form)
else:
return self.form_invalid(form, role_form)
def form_valid(self, form, role_form):
"""
Called if all forms are valid. Creates a Recipe instance along with
associated Ingredients and Instructions and then redirects to a
success page.
"""
self.object = form.save()
role_form.instance = self.object
role_form.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, role_form):
"""
Called if a form is invalid. Re-renders the context data with the
data-filled forms and errors.
"""
return self.render_to_response(
self.get_context_data(form=form,
role_form=role_form))
These settings lead to the error message <class 'rightmanagement.models.Role'> has no ForeignKey to <class 'rightmanagement.models.User'>.
Doing some research I found this: Django inlineformset_factory and ManyToMany fields. It seems like inline formsets are only for ForeignKey but not for ManyToManyField. Also the docs can be interpreted like this.
However, I think in this particular case a foreign key instead of a many-to-many relation wouldn't make any sense. How would a pendant to Django's built-in inline formset look like for many-to-many relations? The aim would be to build a form that allows either the assignment of the user to roles that already exist or create new roles and assign them to the user if they do not exist yet.
As you're probably aware, you can't edit many-to-many relationships with inline formsets. You can, however, edit the through model. So for your inline formset, you just need to set the model to the through model, like so:
RoleFormSet = inlineformset_factory(UserRole, User.role.through)