Indirect inline in Django admin - python

I have the following models:
class UserProfile(models.Model):
user = models.OneToOneField(User)
class Property(models.Model):
user = models.ForeignKey(User)
I would like to create a TabularInline displaying every Property connected to a particular UserProfile on its Django admin page. The problem here is, of course, that Property does not have a ForeignKey directly to UserProfile, so I cannot simply write
class PropertyTabularInline(admin.TabularInline):
model = Property
class UserProfileAdmin(admin.ModelAdmin):
inlines = (PropertyTabularInline,)
How can I easily do what I want?

You can overwrite the User admin page to display both the Profile and the Property models.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from myapp.models import *
class ProfileInline(admin.TabularInline):
model = Profile
class PropertyInline(admin.TabularInline):
model = Property
class UserAdmin(UserAdmin):
inlines = (ProfileInline, PropertyInline,)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
You can also remove any unwanted/unused User properties from being displayed (e.g. Groups or Permissions)
more here: https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#extending-the-existing-user-model
and here:
https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#a-full-example

class PropertyTabularInline(admin.TabularInline):
model = Property
def formfield_for_dbfield(self, field, **kwargs):
if field.name == 'user':
# implement your method to get userprofile object from request here.
user_profile = self.get_object(kwargs['request'], UserProfile)
kwargs["queryset"] = Property.objects.filter(user=user_profile)
return super(PropertyInLine, self).formfield_for_dbfield(field, **kwargs)
once this is done, you can add this inline to user UserProfileAdmin like:
class UserProfileAdmin(admin.ModelAdmin):
inlines = (PropertyTabularInline,)
Haven't tested it, but that should work.

It is achievable by making one change in your models.
Instead of creating OneToOne relationship from UserProfile to User, subclass User creating UserProfile. Code should look like that:
class UserProfile(User):
# some other fields, no relation to User model
class Property(models.Model):
user = models.ForeignKey(User)
That will result in creating UserProfile model that have hidden OneToOne relation to User model, it won't duplicate user model.
After doing that change, your code will work. There are some changes under the hood, like UserProfile no longer have it's own ID, you can access fields from User inside UserProfile and it's hard to swap User model using settings.AUTH_USER_MODEL (that will require creating some custom function returning proper type and changing migration by hand) but if this is not a problem for you, it may be good solution.

Related

I want to create custom signup form and add extra fields in Django default user model

I want to add full name instead of first and last name and I also want to add some others fields like address, phone number, city.
from django.forms import ModelForm
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms
class CreateUserForm(UserCreationForm):
full_name=forms.CharField(max_length=50,required=True)
phone_number=forms.CharField(widget=forms.TextInput(attrs={'type':'number'}))
address=forms.CharField(max_length=200,required=True)
city=forms.CharField(max_length=200,required=True)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2','full_name','phone_number','address','city')
def register(self):
self.save()
I created form by using this method. First, created forms.py for extra fields then inherited it. It is working; but still some fields disappear.
Because, you are adding additional fields to the default user model. First you have to
-Create a Custom User Model by using AbstractUser
Then
-Create a Custom Form for UserCreationForm
You can search google for:
Extend-existing-user-model-in-django

How to save data from the User form that is implemented by built-in auth. User using UserCreationForm in Django?

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.

Adding UserProfile field value when creating User

I've gotten this far with UserProfiles on Django 1.4.5. It works, but now I would like to be able to add a value to my custom field in the admin when creating the user. The way this works, I need to create the new user, then go back and add the UserProfile field.
Where and what do I need to do to add the UserProfile field upon User creation?
### admin.py
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'profile'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
# Something here?
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
### models.py
class UserProfile(models.Model):
"""Create additional fields for users.
Site ID
"""
# This field is required
user = models.OneToOneField(User)
# Additional fields to add.
site_id = models.IntegerField(null=True, blank=True, verbose_name='Site ID')
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
# Or maybe here?
post_save.connect(create_user_profile, sender=User)
It turns out I was actually running into this issue. This post solved it.
Django - UserProfile m2m field in admin - error

Making a foreign key User model extension in Django required

I am extending the Django User model to include a foreign key pointing at another model like so (just like it says in the Django docs):
models.py:
class Ward(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
# Extending the user model
class WardMember(models.Model):
user = models.OneToOneField(User)
ward = models.ForeignKey(Ward)
def __unicode__(self):
return self.ward.name
admin.py:
class WardMemberInline(admin.StackedInline):
model = WardMember
can_delete = False
verbose_name_plural = 'ward member'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (WardMemberInline, )
admin.site.register(Ward)
# Re-register UserAdmin to get WardMember customizations
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
When I create a new user in the admin interface I want this new WardMember.ward extension to be required. Currently it's not enforcing that. Here's what happens:
Create user succeeds without a ward
Create other records as user succeed
Edit user now won't let me save unless there is a ward selected
I'd really like #1 above to fail.
I've tried figuring out how to override save() for User using a proxy object but that's not working. I looked into the pre_save signal but the docs explicitly say that's not for vetoing saves.
What is the right approach?
Additional information:
I'm using 1.4. I see that in 1.5 I can extend the user class but I'm not in a position to update to 1.5 just yet.
I ended up forging ahead with Django 1.5, but I'll leave this here in case someone has a final answer to contribute that works with 1.4.
In django 1.3.1 I use this code and works fine:
from django.contrib.auth.models import User
class FilterSearchQueries(models.Model):
title = models.CharField(max_length=250)
owner = models.ForeignKey(User)
place = models.CharField(max_length=250)
query = models.TextField()

Save M2M "Through" Inlines in Django Admin

Apparently Django's ModelAdmin/ModelForm doesn't allow you to use save_m2m() if there's an intermediate through table for a ManyToManyField.
models.py:
from django.db import models
def make_uuid():
import uuid
return uuid.uuid4().hex
class MyModel(models.Model):
id = models.CharField(default=make_uuid, max_length=32, primary_key=True)
title = models.CharField(max_length=32)
many = models.ManyToManyField("RelatedModel", through="RelatedToMyModel")
def save(self, *args, **kwargs):
if not self.id:
self.id = make_uuid()
super(GuidPk, self).save(*args, **kwargs)
class RelatedModel(models.Model):
field = models.CharField(max_length=32)
class RelatedToMyModel(models.Model):
my_model = models.ForeignKey(MyModel)
related_model = models.ForeignKey(RelatedModel)
additional_field = models.CharField(max_length=32)
admin.py:
from django import forms
from django.contrib import admin
from .models import MyModel
class RelatedToMyModelInline(admin.TabularInline):
model = MyModel.many.through
class MyModelAdminForm(forms.ModelForm):
class Meta:
model = MyModel
class MyModelAdmin(admin.ModelAdmin):
form = MyModelAdminForm
inlines = (RelatedToMyModelInline, )
admin.site.register(MyModel, MyModelAdmin)
If I save MyModel first and then add a new related through model via the inline it works fine, but if I try to set the inline while also adding data for a new MyModel, I get the Django Admin error "Please correct the error below." with nothing highlighted below.
How can I have it save MyModel and then save the inline intermediary models after? Clearly Django can save the through model once it has saved MyModel - so I'm just looking for a hook into that. I tried overriding the form's save() method by calling save_m2m() after calling instance.save(), but apparently that doesn't work for M2Ms with a through table.
I'm using Django 1.2, but this is still an issue in 1.3.
UPDATE: Well, I made a test app like above to isolate the problem, and it appears that it works as expected, correctly saving the M2M intermediary object after saving the MyModel object... as long as I let Django automatically create the MyModel.id field when running python manage.py syncdb - once I added the GUID id field, it no longer works.
This smells more and more like a Django bug.
In your MyModelAdmin you might try overriding the save_formset method. This way you can choose the order in which you save.

Categories

Resources