Generating django admin and foreignkey error - python

Here is my model.py :
class MireilleUser(models.Model):
created = models.DateTimeField( blank=True, editable=False,default=timezone.now)
modified = models.DateTimeField( blank=True,default=timezone.now)
uuid = models.CharField(blank=True, max_length=48,default='')
firebase_id = models.CharField(max_length=256)
def save(self, *args, **kwargs):
""" On save, update timestamps """
if not self.id:
self.created = timezone.now()
self.modified = timezone.now()
if not self.uuid:
self.uuid = str(uuid.uuid4().hex) + str(random.randint(1000, 9999))
return super(MireilleUser, self).save(*args, **kwargs)
class MireilleAppSubscription(models.Model):
ACTIVE = 'AC'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
GRADUATE = 'GR'
STATUS_VALUE = [
(ACTIVE, 'Active'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
]
STRIPE = 'ST'
GOOGLE = 'GO'
APPLE = 'AP'
PLATFORM_VALUE = [
(STRIPE, 'STRIPE'),
(GOOGLE, 'GOOGLE'),
(APPLE, 'APPLE'),
]
created = models.DateTimeField( blank=True, editable=False,default=timezone.now)
modified = models.DateTimeField( blank=True,default=timezone.now)
uuid = models.CharField(blank=True, max_length=48,default='')
mireille_user = models.ForeignKey(MireilleUser,on_delete=models.PROTECT)
date_begin = models.DateTimeField(blank=True, editable=True, default=timezone.now)
stripe_client_id = models.CharField(blank=True, max_length=48,default='')
platform = models.CharField(blank=True, max_length=2,choices=PLATFORM_VALUE)
expected_end_time = models.DateTimeField(blank=True, editable=True, default=(timezone.now()+timezone.timedelta(days=8)))
is_free = models.BooleanField(default=False)
is_vip = models.BooleanField(default=False)
promo_code = models.CharField(blank=True, max_length=128, default='')
status = models.CharField(max_length=2,
choices=STATUS_VALUE,
default=ACTIVE)
def save(self, *args, **kwargs):
""" On save, update timestamps """
if not self.id:
self.created = timezone.now()
self.modified = timezone.now()
if not self.uuid:
self.uuid = str(uuid.uuid4().hex) + str(random.randint(1000, 9999))
return super(MireilleAppSubscription, self).save(*args, **kwargs)
And here is my admin.py :
class MireilleUser_Admin(admin.ModelAdmin):
list_display = [field.name for field in MireilleUser._meta.get_fields()]
search_fields = [field.name for field in MireilleUser._meta.get_fields()]
actions = [
export_as_csv_action(
"CSV Export",
fields=[field.name for field in MireilleUser._meta.get_fields()],
)
]
class MireilleAppSubscription_Admin(admin.ModelAdmin):
list_display = [field.name for field in MireilleAppSubscription._meta.get_fields()]
search_fields = [field.name for field in MireilleAppSubscription._meta.get_fields()]
actions = [
export_as_csv_action(
"CSV Export",
fields=[field.name for field in MireilleAppSubscription._meta.get_fields()],
)
admin.site.register(MireilleUser, MireilleUser_Admin)
admin.site.register(MireilleAppSubscription, MireilleAppSubscription_Admin)
but in the admin when i click on Mireille User on the admin i have :
AttributeError at /admin/AppUser/mireilleuser/
Unable to lookup 'mireilleappsubscription' on MireilleUser or MireilleUser_Admin
I don't understand why because the foreignkey is in MireilleAppSubscription to MireilleUser and not MireilleUser To MireilleAppSubscription
i doubt that there is something in my way of using meta fields for genrating the admin.
Regards

The is because of Django creating a reverse relation--(Django What is reverse relationship?) named mireilleappsubscription and which is not a actual field
I would suggest using the list_display and search_fields by specifying each field one-by-one
class MireilleUser_Admin(admin.ModelAdmin):
list_display = ["created", "modified", "ect"]
search_fields = ["created", "modified", "etc"]
OR
If you want just to igore the error, remove the mireilleappsubscription field from the list as,
fields = [field.name for field in MireilleUser._meta.get_fields()]
fields.remove("mireilleappsubscription")
class MireilleUser_Admin(admin.ModelAdmin):
list_display = fields
search_fields = fields

Related

Take the current admin

serializers.py
class RegSerializer(serializers.ModelSerializer):
admin = serializers.SlugRelatedField(slug_field='username', read_only=True)
class Meta:
model = Registration
fields = [
'id', 'rooms', 'first_name', 'last_name','admin', 'pasport_serial_num', 'birth_date', 'img', 'visit_date',
'leave_date', 'guest_count', 'room_bool']
models.py
class Rooms(models.Model):
objects = None
room_num = models.IntegerField(verbose_name='Комната')
room_bool = models.BooleanField(default=True, verbose_name='Релевантность')
category = models.CharField(max_length=150, verbose_name='Категория')
price = models.IntegerField(verbose_name='Цена (сум)', null=True)
def __str__(self):
return f'{self.room_num}'
class Meta:
verbose_name = 'Комнату'
verbose_name_plural = 'Комнаты'
class Registration(models.Model):
objects = None
rooms = models.ForeignKey(Rooms, on_delete=models.CASCADE, verbose_name='Номер',
help_text='Номер в который хотите заселить гостя!',
)
first_name = models.CharField(max_length=150, verbose_name='Имя')
last_name = models.CharField(max_length=150, verbose_name='Фамилия')
admin = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Администратор')
pasport_serial_num = models.CharField(max_length=100, verbose_name='Серия паспорта', help_text='*AB-0123456')
birth_date = models.DateField(verbose_name='Дата рождения')
img = models.FileField(verbose_name='Фото документа', help_text='Загружайте файл в формате .pdf')
visit_date = models.DateField(
default=django.utils.timezone.localdate, verbose_name='Дата прибытия')
leave_date = models.DateField(blank=True, null=True, verbose_name='Дата отбытия', default='После ухода!')
guest_count = models.IntegerField(default=1, verbose_name='Кол-во людей')
room_bool = models.BooleanField(default=False, verbose_name='Релевантность',
help_text='При бронирование отключите галочку')
price = models.IntegerField(verbose_name='Цена (сум)', null=True)
def __str__(self):
return f'{self.rooms},{self.last_name},{self.first_name},{self.room_bool}'
class Meta:
verbose_name = 'Номер'
verbose_name_plural = 'Регистрация'
how can I make it so that the name of the user who registered room is indicated in the admin field and without the right to change only readonly?
can this be done at all?
thanks in advance for your reply
You can pass additional attributes to serilizer's save method. In your view, you can call serializer save() with admin argument like this:
def your_view(request):
# your code
serializer.save(admin=request.user)
Or if you want to do it on admin page, you can override your admin's save_model method. Also you should specify admin as a readonly:
class RegistrationAdmin(admin.ModelAdmin):
readonly_fields = ('admin',)
def save_model(self, request, obj, form, change):
if not obj.pk:
# Only set admin during the first save.
obj.admin = request.user
super().save_model(request, obj, form, change)
I set serializers.HiddenField and by default set CurrentUserDefault() from serializers
automatically substitutes the value of the current admin and at the same time the admin field now goes to the api
class RegSerializer(serializers.ModelSerializer):
admin = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Registration
exclude = ['price', 'visit_date']

Edit and Add in django

How to allow all fields to be added to the database and only some to be edited in django
class PageAdmin(admin.ModelAdmin):
list_display = ('rooms', 'first_name', 'last_name', 'visit_date','leave_date','admin')
list_filter = ('rooms',)
readonly_fields = ('visit_date',)
admin.site.site_header = 'Uzbegim'
def get_form(self, request, *args, **kwargs):
form = super(PageAdmin, self).get_form(request, *args, **kwargs)
form.base_fields['admin'].initial = request.user
return form
(so that after creation it was impossible to edit a certain field)
class Rooms(models.Model):
objects = None
room_num = models.IntegerField(verbose_name='Комната')
room_bool = models.BooleanField(default=True,verbose_name='Релевантность')
category = models.CharField(max_length=150,verbose_name='Категория')
def __str__(self):
return f'{self.room_num}'
class Meta:
verbose_name = 'Комнату'
verbose_name_plural = 'Комнаты'
class Registration(models.Model):
objects = None
rooms = models.ForeignKey(Rooms, on_delete=models.CASCADE,verbose_name='Номер',help_text='Номер в который хотите заселить гостя!')
first_name = models.CharField(max_length=150,verbose_name='Имя')
last_name = models.CharField(max_length=150,verbose_name='Фамилия')
admin = models.ForeignKey(User, on_delete=models.CASCADE,verbose_name='Администратор')
pasport_serial_num = models.CharField(max_length=100,verbose_name='Серия паспорта',help_text='*AB-0123456')
birth_date = models.DateField(verbose_name='Дата рождения')
img = models.FileField(verbose_name='Фото документа',help_text='Загружайте файл в формате .pdf')
visit_date = models.DateTimeField(
default=datetime.datetime(year=year, month=month, day=day, hour=datetime.datetime.now().hour,
minute=datetime.datetime.now().minute, second=00,),verbose_name='Дата прибытия')
leave_date = models.DateTimeField(
default=datetime.datetime(year=year, month=month, day=day + 1, hour=12, minute=00, second=00),verbose_name='Дата отбытия')
guest_count = models.IntegerField(default=1,verbose_name='Кол-во людей')
room_bool = models.BooleanField(default=False,verbose_name='Релевантность',help_text='При бронирование отключите галочку')

Django admin - How to add request.user as default vaule for a Inline model?

I've written a small support application made out of 2 models, please see below.
As I answere onto support tickets at the django admin panel, I dont always want to set the author name manully for each reply I add to the ticket. Instead I want that request.user I set as author automatically as initial vaule. Sadly I was not able to find any solution at the django docs that seem to solve this issue ...
admin.py
class SupportTicketRepliesInline(admin.TabularInline):
model = SupportTicketReplies
extra = 0
min_num = 1
class SupportTicketsAdmin(admin.ModelAdmin):
list_display = ['requester', 'creation_date', 'status', 'category', 'subject']
ordering = ['-creation_date']
list_filter = ['creation_date']
inlines = [
SupportTicketRepliesInline,
]
admin.site.register(SupportTickets, SupportTicketsAdmin)
models.py
...
class SupportTickets(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
requester = models.ForeignKey(User, on_delete=models.CASCADE, null=False, blank=False)
category = models.IntegerField(choices=TICKET_CATEGORY, verbose_name='Ticket Category')
subject = models.CharField(max_length=30)
description = models.TextField(max_length=2000, blank=False, verbose_name='Problem description')
status = models.IntegerField(choices=STATUS_OF_TICKET, verbose_name='Ticket Status', default=2)
creation_date = models.DateTimeField(auto_now_add=True, blank=False)
def publish(self):
self.creation_date = timezone.now()
self.save()
class Meta:
verbose_name = "Support Ticket"
verbose_name_plural = "Support Tickets"
ordering = ['-creation_date']
models.py
class SupportTicketReplies(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
ticket = ForeignKey(SupportTickets, related_name='replies', on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Author', blank=True)
content = models.TextField(verbose_name="Content", max_length=2000)
creation_date = models.DateTimeField(auto_now_add=True, blank=False)
class Meta:
verbose_name = "Ticket Reply"
verbose_name_plural = "Ticket Replies"
ordering = ['creation_date']
i think everything what you need is :
https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey
it will look smrh like:
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "author":
self.fields['author'].queryset = UserModel.objects.filter(id=request.usermodel.id)
also you should remove blank=True from your model.
or you can just add to your inline class as initial value:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['author'].initial = self.request.user
The following works for me:
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "author":
author = request.user
if author:
kwargs['initial'] = author.pk
return super(SupportTicketRepliesInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
At a admin.TabularInline or admin.StackedInline

Filtering in Django ModelViewSet

I don't think I'm doing this correctly. What I'm trying to do is prevent data from being returned if it doesn't match my criteria. Here are the criteria:
User should be able to see the project if:
If the object is private and they are the owner
-- OR --
The project is not private
If the user is the owner, or they are a member of the assigned group
EDITED PER THE COMMENT:
The code below seems to work, but I'm still not sure if this is the correct logic or the right way to do this.
api.py
class ProjectListViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all().order_by('name')
serializer_class = ProjectLightSerializer
authentication_classes = [TokenAuthentication, ]
permission_classes = [IsAuthenticated, ]
def list(self, request, *args, **kwargs):
projects = []
queryset = super().get_queryset()
is_private = queryset.values('is_private')
owner = queryset.filter(owner__exact=self.request.user)
if not self.request.user.is_superuser:
if is_private and not owner:
return Response(data=[])
elif is_private and owner:
projects = queryset.filter(groups__in=self.request.user.groups.all())
else:
projects = super().get_queryset()
projects = self.filter_queryset(projects)
serializer = self.get_serializer(projects, many=True)
result_set = serializer.data
return Response(result_set)
serializers.py
class ProjectLightSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField()
slug = serializers.CharField()
description = serializers.CharField()
groups = GroupSerializer(many=True)
created_date = serializers.DateTimeField()
modified_date = serializers.DateTimeField()
owner = UserSerializer()
is_private = serializers.BooleanField()
models.py
class Project(models.Model):
name = models.CharField(max_length=60, help_text=_("Name of project"))
slug = models.SlugField(default="")
groups = models.ManyToManyField(Group, help_text=_("Attached workgroup"))
description = models.TextField(null=False, blank=False,
verbose_name=_("description"))
logo = models.FileField(upload_to=get_project_logo_file_path,
max_length=500, null=True, blank=True,
verbose_name=_("logo"))
created_date = models.DateTimeField(null=False, blank=False, verbose_name=_("created date"), auto_now_add=True)
modified_date = models.DateTimeField(null=False, blank=False, auto_now_add=True, verbose_name=_("modified date"))
owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True,
related_name="owned_projects", verbose_name=_("owner"), on_delete=models.CASCADE)
is_private = models.BooleanField(default=True, null=False, blank=True,
verbose_name=_("is private"))
tags = TaggableManager(help_text=_('A comma-separated list of tags.'), blank=True, through=TaggedItem,
to=Tag, verbose_name='Tags')
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)[:255]
while type(self).objects.filter(slug=self.slug).exists():
match_obj = re.match(r'^(.*)-(\d+)$', self.slug)
if match_obj:
next_int = int(match_obj.group(2)) + 1
self.slug = match_obj.group(1) + "-" + str(next_int)
else:
self.slug += '-2'
super(Project, self).save(*args, **kwargs)
def get_tags_display(self):
return self.tags.values_list('name', flat=True)
class Meta:
db_table = 'projects'
ordering = ["name", "id"]
verbose_name = "Project"
verbose_name_plural = "Projects"
Any assistance would be greatly appreciated. Thanks in advance.
You can override the get_queryset method instead of list
from django.db.models import Q
class ProjectListViewSet(viewsets.ModelViewSet):
serializer_class = ProjectLightSerializer
authentication_classes = [TokenAuthentication, ]
permission_classes = [unauthenticated, ]
def get_queryset(self, request, *args, **kwargs):
queryset = super().get_queryset(self, request, *args, **kwargs)
is_private_query = Q(is_private=True, owner=self.request.user)
groups_user_is_part_of = self.request.user.groups().values_list('id', flat=True)
is_not_private_query = Q(is_private=False) & (Q(owner=self.request.user) | Q(groups__id__in=groups_user_is_part_of))
return queryset.filter(is_private_query | is_not_private_query).order_by('name')
More here https://docs.djangoproject.com/en/3.0/topics/db/queries/#complex-lookups-with-q-objects

Django : Edit the many to many field Inline using Django Admin

I want to edit the cuisines associated with a dish on the dish panel in django admin. I am trying to use InlineModelAdmin. The problem is that I can edit the DishCuisinesMap objects but not the cuisines object.
Here is the screenshot:
This is my models.py:
class Cuisines(models.Model):
cuisine_id = models.IntegerField(primary_key=True)
cuisine_mtom = models.ManyToManyField('DishInfo', through='DishCuisinesMap')
name = models.TextField()
cuisine_sf_name = models.TextField()
type = models.IntegerField()
insert_time = models.DateTimeField()
update_time = models.DateTimeField()
class Meta:
managed = False
db_table = 'cuisines'
class DishCuisinesMap(models.Model):
dish = models.ForeignKey('DishInfo', on_delete=models.PROTECT,
related_name='dcm_dish')
cuisine = models.ForeignKey(Cuisines, on_delete=models.PROTECT,
related_name='dcm_cuisine')
insert_time = models.DateTimeField()
update_time = models.DateTimeField()
class Meta:
managed = False
db_table = 'dish_cuisines_map'
unique_together = (('dish', 'cuisine'),)
class DishInfo(models.Model):
dish_id = models.BigIntegerField(primary_key=True)
bid = models.ForeignKey(Brands, on_delete=models.PROTECT, db_column='bid',
related_name='dinfo_brand')
name = models.TextField()
is_live = models.IntegerField()
veg_nonveg_ind = models.SmallIntegerField(blank=True, null=True)
sf_name = models.TextField()
descr = models.TextField(blank=True, null=True)
expert_tag = models.TextField(blank=True, null=True)
special_desc = models.TextField(blank=True, null=True)
reco_percent = models.IntegerField(blank=True, null=True)
one_liner = models.TextField(blank=True, null=True)
nutrition = JSONField()
insert_time = models.DateTimeField()
update_time = models.DateTimeField()
images = ArrayField(models.TextField())
class Meta:
managed = False
db_table = 'dish_info'
unique_together = (('bid', 'name'), ('bid', 'sf_name'),)
def __unicode__(self):
brand_name = self.bid.name
return self.name
and this is my admin.py:
class CityDishFilter(admin.SimpleListFilter):
title = ('city name')
parameter_name = 'city_id'
def lookups(self, request, model_admin):
list_of_cities = list()
queryset = Cities.objects.all()
for city in queryset:
list_of_cities.append(
(str(city.city_id), city.name)
)
return list_of_cities
def queryset(self, request, queryset):
query_params = request.GET
if self.value():
city_query = DelLocations.objects.filter(city__city_id=self.value())\
.values('del_id')
loc_query = DelLocationsMapping.objects.filter(del_loc__in=
city_query).values('plot')
dopm_query = DishOutletPlatMapping.objects.filter(plot__in
=loc_query).values('dish')
final_query = DishInfo.objects.filter(dish_id__in=dopm_query)
if 'veg_nonveg_ind' in query_params:
final_query = final_query.filter(veg_nonveg_ind=query_params.get('veg_nonveg_ind'))
if 'is_live' in query_params:
final_query = final_query.filter(is_live=query_params.get('is_live'))
return final_query
return queryset
class BrandDishFilter(admin.SimpleListFilter):
title = ('brand name')
parameter_name = 'brand_id'
def lookups(self, request, model_admin):
query_params = request.GET
list_of_brands = list()
if 'city_id' in query_params:
city_query = DelLocations.objects.filter(city__city_id=query_params.get('city_id'))\
.values('del_id')
loc_query = DelLocationsMapping.objects.filter(del_loc__in=
city_query).values('plot')
dopm_query = DishOutletPlatMapping.objects.filter(plot__in
=loc_query).values('dish')
dish_query = DishInfo.objects.filter(dish_id__in=dopm_query).\
values('bid').distinct()
brand_query = Brands.objects.filter(bid__in=dish_query).order_by('name')
for brand in brand_query:
list_of_brands.append(
(str(brand.bid), brand.name)
)
return list_of_brands
else:
brand_query = Brands.objects.all().order_by('name')
for brand in brand_query:
list_of_brands.append(
(str(brand.bid), brand.name)
)
return list_of_brands
def queryset(self, request, queryset):
if 'brand_id' in request.GET:
queryset = queryset.filter(bid=self.value())
return queryset
return queryset
class DishCuisinesInline(admin.TabularInline):
model = DishCuisinesMap
extra = 1
class CuisinesAdmin(admin.ModelAdmin):
inlines = [DishCuisinesInline,]
fields = ("name", "cuisine_sf_name", "type")
class DishInfoAdmin(admin.ModelAdmin):
list_select_related = ('bid',)
list_display = ('name', 'brand_name')
fieldsets = (
(None, {'fields': ('name', 'sf_name', 'is_live', 'veg_nonveg_ind',
'one_liner',
)
}
),
('Advanced options', {'classes': ('collapse',),
'fields': ('descr', 'images')
}
)
)
search_fields = ['name', 'bid__name']
list_filter = ('veg_nonveg_ind', 'is_live', CityDishFilter, BrandDishFilter) #, 'bid__name'
inlines = [DishTimingsInline, DishCuisinesInline]
# changing the size of the text fields:
formfield_overrides = {
models.TextField: {'widget': Textarea(
attrs = {'rows': 4,
'cols': 50})
},
}
def brand_name(self, obj):
return obj.bid.name
admin.site.register(DishInfo, DishInfoAdmin)
admin.site.register(Cuisines, CuisinesAdmin)
The django docs here say that membership objects can be edited from Person or the Group detail pages, but what is way to edit the group from the person details page?
In my case I need a way to edit the cuisines from the dish page , I am pretty new to django. Any help is greatly appreciated.

Categories