Hi i have a django model for notification which have a many-to-many relation but nothing appears in django admin ( all fields do not appear)
class Notification(models.Model):
"""send notification model"""
title = models.CharField(max_length=200)
text = models.TextField(null=True, blank=True)
device = models.ManyToManyField(Device, null=True, blank=True)
country = models.ManyToManyField(Country, null=True, blank=True)
sent = models.BooleanField(default=False)
when i open django admin for this model and press add notification this is what happens (nothing appears)
Country and Device Code
class Device(models.Model):
"""Store device related to :model:`accounts.User`."""
user = models.OneToOneField(User, related_name='device', on_delete=models.CASCADE)
model = models.CharField(max_length=200, blank=True, null=True)
player_id = models.CharField(max_length=200, blank=True, null=True)
class Meta:
verbose_name = 'Device'
verbose_name_plural = 'Devices'
def __str__(self):
return self.model
class Country(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
Admin.py
from django.contrib import admin
from .models import Notification
admin.site.register(Notification)
Edit:
Thank you all the problem is solved
The problem was caused by some entries in device model that did have None in the model field so there was a problem displaying it correctly.
According to https://code.djangoproject.com/ticket/2169 :
When a class has a field that isn't shown in the admin interface but
must not be blank, it's impossible to add a new one. You get a cryptic
"Please correct the error below." message with no shown errors. The
error message should probably say something about a hidden field.
Now ManyToManyFields don't need null=True, try removing those statements and see if you get an improvement.
Also, try adding the Country and Device models in admin.py so admin can see them and display them.
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#working-with-many-to-many-models
Define an inline for the many-to-manys in admin.py:
from django.contrib import admin
class DeviceInline(admin.TabularInline):
model = Notification.device.through
class CountryInline(admin.TabularInline):
model = Notification.country.through
class NotificationAdmin(admin.ModelAdmin):
inlines = [
DeviceInline, CountryInline
]
exclude = ("device", "country")
Related
I have a model called listings and I want staff users to only be able to view, edit, delete listings in the admin panel that they created. Currently staff users can view edit and delete all of the listings
here is my listings/admin.py
from django.contrib import admin
from .models import Listing
class ListingAdmin(admin.ModelAdmin):
list_display =('id','Full_Name','Is_Published','Town_Or_City','District','Region','List_Date')
list_display_links = ('id','Full_Name')
list_editable = ('Is_Published',)
search_fields = ('Full_Name','Town_Or_City','District','Region',)
admin.site.register(Listing, ListingAdmin)
here is my listings/models.py
from django.db import models
from datetime import datetime
from FuneralHomes.models import FuneralHome
class Listing(models.Model):
index = models.ForeignKey(index, on_delete=models.DO_NOTHING,blank=True)
Full_Name = models.CharField(max_length=200)
First_Name = models.CharField(max_length=200)
Last_Name = models.CharField(max_length=200)
Nee = models.CharField(max_length=200, blank=True)
Town_Or_City = models.CharField(max_length=200)
District = models.CharField(max_length=200, blank=True)
Region = models.CharField(max_length=200)
List_Date = models.DateField(max_length=200)
Photo = models.ImageField(upload_to='photos/%Y/%m/%d', blank=True)
Is_Published = models.BooleanField(default=True)
List_Date = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.Full_Name
The admin panel really isn't the place for things like this (as explained in the first paragraph of the Django documentation).
A quick a dirty way of accomplishing what you're trying to do is probably overriding the delete method for this model to check if the user created it. For only listing the user's posts you could utilize the Manager class. Finally, to handle editing, you would have to override the save method to see if it already exists and if the user created it.
you can override get_queryset function and just filter listings related to that user , in this case user can only see his listings .
class ListingAdmin(admin.ModelAdmin):
def get_queryset (self, request):
return Listing.objects.filter(listing_user = request.user)
I have a Slider module that i want to include items from movies_movie and shows_show table. An item can either be a show or movie. How do i make user select between movie and show? Currently i have columns for movie and show but how do i force user to select between the two?
also title_en is a column in movie or tv show tables. So the title of the movie/show selected should display in row after save.
class Slider_items(models.Model):
order = models.IntegerField(max_length=3, blank=True)
movie = models.ForeignKey('movies.movie', on_delete=models.CASCADE, blank=True)
show = models.ForeignKey('shows.show', on_delete=models.CASCADE, blank=True)
def __str__(self):
return self.title_en
class Meta:
verbose_name = "Slider Items Module"
verbose_name_plural = "Slider Item Module"
Also if a show is selected and a movie isn't, how do i know title_en will be taken from show and not movie?
I think you can do something like this:
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
class Slider_items(models.Model):
order = models.IntegerField(max_length=3, blank=True)
# don't forget to add null=True to both fields
movie = models.ForeignKey('movies.movie', on_delete=models.CASCADE, blank=True, null=True)
show = models.ForeignKey('shows.show', on_delete=models.CASCADE, blank=True, null=True)
# see docs, https://docs.djangoproject.com/en/3.2/ref/models/instances/#django.db.models.Model.clean
def clean(self):
if self.movie and self.show:
raise ValidationError({'movie': _('You can't select both types at the same time')})
elif not self.movie and not self.show:
raise ValidationError({'movie': _('You must select one type')})
def __str__(self):
return self.movie.title_en if self.movie else self.show.title_en
class Meta:
verbose_name = "Slider Items Module"
verbose_name_plural = "Slider Item Module"
You may consider using django contenttypes.
Imagine in the future, you have not just Movie, Show, but have new Class such as Book, Podcase, it might not be a good idea to keep adding new foreignkey to your Slider Model.
I have not used contenttype before, so I am referencing this SO answer.
(using python 3.6, django 3.2)
models.py
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Movie(models.Model):
title = models.CharField(max_length=50)
director = models.CharField(max_length=50)
class Show(models.Model):
title = models.CharField(max_length=50)
date = models.DateField()
class Slider(models.Model):
order = models.IntegerField(max_length=3, blank=True)
choices = models.Q(model='movie') | models.Q(model='show')
selection_type = models.ForeignKey(
ContentType, limit_choices_to=choices,
on_delete=models.CASCADE)
selection_id = models.PositiveIntegerField()
selection = GenericForeignKey('selection_type', 'selection_id')
def __str__(self):
return self.selection.title
admin.py
#admin.register(Slider)
class SliderAdmin(admin.ModelAdmin):
pass
at django shell, the following is valid.
movie = Movie.objects.create(title='movie 1', director='ben')
show = Show.objects.create(title='show 1', date='2021-01-01')
s1 = Slider.objects.create(selection=movie, order=1)
s2 = Slider.objects.create(selection=show, order=2)
However, using limit_choices_to only restrict the choices in admin page, and there is no constraint at database level. i.e. the following are actually legal.
place = Place.objects.create(name='home')
s3 = Slider.objects.create(selection=s3, order=3)
I have not found a fix for this issue yet. Maybe doing some validation in save method is a way (see the comments under this).
I'm trying to figure it out on how I can show only a specific set of dynamic fields in eav to a unique registered model in my apps.models. But I don't know how to this, I've also read the documents but I can't seem to find anything about it, or maybe I've come across it and didn't understand.
Now, what is happening is that, when I add an attribute in the django admin. It also adds the dynamic field in all the models registered in the eav.
What I want to do is that;
model 1 - dynamic_field1, dynamic_field2, dynamic_field3
model 2 - dynamic_field4, dynamic_field5, dynamic_field6
Btw, I'm currently using the django-eav2 the documentation is in the link. I've found my solution for my initial use case here link
Below codes are basically on how to register my models to the eav. Here is my sample models
class ClientName(models.Model):
name = models.CharField(max_length=250, null=True, blank=True)
description = models.TextField(null=True, blank=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return str(self.name)
class CallDetails(models.Model):
client_name = models.ForeignKey(ClientName, on_delete=models.PROTECT, null=True, blank=True, db_index=True)
letter_info = models.TextField(null=True, blank=True)
def __str__(self):
return str(self.client_name)
class Meta:
verbose_name = 'Call Detail'
ordering = ['client_name']
eav.register(ClientName)
eav.register(CallDetails)
below is my admin.py
class CallDetailsAdminForm(BaseDynamicEntityForm):
model = CallDetails
class CallDetailsAdmin(BaseEntityAdmin):
form = CallDetailsAdminForm
admin.site.register(CallDetails, CallDetailsAdmin)
I have created a model as below.
class UserPost(models.Model):
author = models.ForeignKey(User, related_name='userpost', null=True, on_delete=models.CASCADE)
post_date = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=150, blank=False)
post_body = models.TextField(blank=True, null=True, default='text')
image = models.ImageField(upload_to='post_pics', blank=True)
likes = models.ManyToManyField(User, blank=True, related_name='post_likes')
I am not populating likes field anywhere, my admin screenshot is below.Why my likes field is getting populated with all the users created?
admin screenshot
admin.py
from django.contrib import admin
from feed.models import UserPost
# Register your models here.
admin.site.register(UserPost)
Edit 1:
Adding a screenshot for Rishabh's answer.
trying to add user from left as suggested by him
You are using ManyToManyField of Django which will show you all records of User table left side and you can add them by double clicking on them or by clicking '+' sign, so your likes field is not prepopulated at all it is just showing User table data.
I have a Django app that works perfectly on google app engine, using the datastore via djangae. However, the admin site throws an error:
NotSupportedError at /admin/auth/user/5629499534213120/change/
Cross-join where filters are not supported on the Datastore
This error only occurs when trying to edit the default Django user model. Not sure why this is happening.
I have used the default Django user model. (this is an app dealing with donations for a nonprofit)
models.py:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class FoodSplashUser(models.Model):
base_user = models.OneToOneField(User, on_delete=models.CASCADE)
address = models.TextField(null=True)
city = models.TextField(null=True)
state = models.CharField(max_length=4, null=True)
zip = models.CharField(max_length=10, null=True)
def __str__(self):
return str(self.base_user.username)
class Organization(models.Model):
base_user = models.OneToOneField(User, on_delete=models.CASCADE)
address = models.TextField(null=True)
city = models.TextField(null=True)
state = models.CharField(max_length=4, null=True)
zip = models.CharField(max_length=10, null=True)
description = models.TextField(null=True)
image_url = models.URLField(null=True)
def __str__(self):
return str(self.base_user.username)
class DonationRequest(models.Model):
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now=True)
request_type = models.TextField(null=True)
description = models.TextField(null=True)
def __str__(self):
return str(self.organization.base_user.username) + " " + self.request_type
class DonationPromise(models.Model):
user = models.ForeignKey(FoodSplashUser, on_delete=models.CASCADE)
donation_request = models.ForeignKey(DonationRequest, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now=True)
verified = models.BooleanField(default=False)
def __str__(self):
return str(self.user.base_user.username) + " " + str(self.donation_request)
This app goes with the default Django admin interface, but I decided to make the classes below for easy editing later.
admin.py:
from django.contrib import admin
from . import models
# Register your models here.
class FoodSplashUserAdmin(admin.ModelAdmin):
pass
class OrganizationAdmin(admin.ModelAdmin):
pass
class DonationRequestAdmin(admin.ModelAdmin):
pass
class DonationPromiseAdmin(admin.ModelAdmin):
pass
admin.site.register(models.FoodSplashUser, FoodSplashUserAdmin)
admin.site.register(models.Organization, OrganizationAdmin)
admin.site.register(models.DonationRequest, DonationPromiseAdmin)
admin.site.register(models.DonationPromise, DonationPromiseAdmin)
This may be a separate error, but :
admin.site.register(models.DonationRequest, DonationPromiseAdmin)
admin.site.register(models.DonationPromise, DonationPromiseAdmin)
Shouldn't that first one be: DonationRequestAdmin?
NotSupportedError indicates that your code performs an action that is not possible with App Engine Datastore. Not all the Django ORM features can be used in a non-relational database which Datastore is. You are trying to create an entity that has some relations, which causes the error. Probably it is a good idea to use Gauth for authentication and user management, as described in the Djangae docs.