Edit and Add in django - python

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='При бронирование отключите галочку')

Related

Validate models in django admin with inlines (when I save several models at the time)

I'm maiking a quiz on django.
On the picture below you can see 3 models (Quiz, QuizQuestionQuizAnswer) on 1 page.
I used NestedStackedInline and NestedTabularInline for that.
I need to need validate quiz when I save of edit forms.
For example:
I need to check if at least one answer is marked as correct.
If answers more than one.
etc
models.py
class Quiz(models.Model):
title = models.CharField('Название теста', max_length=200)
description = models.TextField('Описание', max_length=2000, blank=True)
owner = models.ForeignKey(User, on_delete=models.DO_NOTHING)
pass_score = models.PositiveIntegerField(help_text='Минимальный результат (в процентах) для прохождения теста',
default=60,
validators=[
MaxValueValidator(100),
])
created_at = models.DateTimeField('Дата создания', auto_now_add=True, )
updated_at = models.DateTimeField('Дата обновления', auto_now=True, )
def get_quiz_question(self):
return self.quizquestion_set.all()
def __str__(self):
return self.title
class QuizQuestion(models.Model):
""" Вопросы для квиза"""
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
question = models.CharField('Вопрос', max_length=1000)
created_at = models.DateTimeField('Дата создания', auto_now_add=True, )
updated_at = models.DateTimeField('Дата обновления', auto_now=True, )
def __str__(self):
return self.question
class Meta:
verbose_name = 'Тест'
verbose_name_plural = 'Тесты'
class QuizAnswer(models.Model):
""" Варианты ответов """
question = models.ForeignKey(QuizQuestion, on_delete=models.CASCADE)
text = models.CharField('Варианты ответа', max_length=250)
is_correct = models.BooleanField('Отметьте правильные', default=False)
class Meta:
verbose_name = 'Ответ'
verbose_name_plural = 'Ответы'
def __str__(self):
return f'Вариант ответа'
admins.py
from quiz.models import *
from django.contrib import admin
from nested_inline.admin import NestedStackedInline, NestedModelAdmin, NestedTabularInline
class AnswerInLine(NestedTabularInline):
""" Делаем вложенную модель в админке"""
model = QuizAnswer
extra = 1
class QuestionInLine(NestedStackedInline):
""" Делаем вложенную модель в админке"""
model = QuizQuestion
extra = 2
inlines = [AnswerInLine]
def save_model(self, request, obj, form, change):
pass
class QuizAdmin(NestedModelAdmin):
# добавляет эти поля в админку приложения
# list_display = ('title','description','pass_score')
model = Quiz
inlines = [QuestionInLine]
readonly_fields = ('owner', 'created_at', 'updated_at')
def save_model(self, request, obj, form, change):
if not obj.pk:
# Only set added_by during the first save.
obj.owner = request.user
super().save_model(request, obj, form, change)
class CategoryAdmin(admin.ModelAdmin):
list_display = ("id", 'title')
list_display_links = ('id', 'title')
search_fields = ('title',)
# регистрирует модуль и его параметры
admin.site.register(Quiz, QuizAdmin)

Null in response which should't exist Django

When I send request in Postman like this:
it returns me all fields fine expect the profile_photo. profile_photo in response is null and I don't know what is the problem. It should be the new uuid photo name.
Here is my model:
class User(AbstractBaseUser, PermissionsMixin):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(max_length=150, blank=True)
last_name = models.CharField(max_length=150, blank=True)
city = models.CharField(max_length=150, blank=True)
description = models.CharField(max_length=1000, blank=True)
profile_photo = models.CharField(max_length=500, blank=True)
date_joined = models.DateTimeField(default=timezone.now)
about = models.TextField(_(
'about'), max_length=500, blank=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = CustomAccountManager()
object = models.Manager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'city']
def __str__(self):
return self.email
This is my view:
class CustomUserUpdate(generics.UpdateAPIView):
permission_classes = [IsAuthenticated]
queryset = User.objects.all()
serializer_class = UserUpdateSerializer
def get_object(self):
return self.request.user
This is my serializer. Here i am setting the new photo name. When I print the new name here like this: print(instance.profile_photo) it shows me the new file name fine. But in the response i get null.
class UserUpdateSerializer(serializers.ModelSerializer):
profile_photo = serializers.FileField(required=False)
class Meta:
model = User
fields = ('email', 'first_name', 'last_name', 'city', 'description', 'profile_photo')
def __init__(self, *args, **kwargs):
super(UserUpdateSerializer, self).__init__(*args, **kwargs)
self.fields['email'].required = False
self.fields['description'].required = False
def update(self, instance, validated_data):
if instance.id == self.context['request'].user.id:
instance.email = validated_data.get('email', instance.email)
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.city = validated_data.get('city', instance.city)
instance.description = validated_data.get('description', instance.description)
uploaded_file = validated_data.get('profile_photo', None)
if uploaded_file:
validate_extension(uploaded_file.name)
instance.profile_photo = handle_uploaded_file(uploaded_file)
instance.save()
return instance
def handle_uploaded_file(file):
extension = os.path.splitext(file.name)[1]
new_filename = f"{uuid.uuid4()}{extension}"
destination = open(f'static/user/images/{new_filename}', 'wb+')
for chunk in file.chunks():
destination.write(chunk)
destination.close()
return new_filename
def validate_extension(filename):
extension = os.path.splitext(filename)[1].replace(".", "")
if extension.lower() not in ALLOWED_IMAGE_EXTENSIONS:
raise serializers.ValidationError(
(f'Invalid uploaded file type: {filename}'),
code='invalid',
)
While sending requests you are passing file as input to the serializer. Serializer validates it and saves it. Till here it is perfectly fine.
Now while returning the response it expects a file from instance.profile_photo but to the serializer validator's surprise, it contains a string value (i.e UUID file name). The problem is here!
We got the bug point. Let's solve it.
To solve it, differentiate the names for the request(File) and response (File name i.e UUID string):
class UserUpdateSerializer(serializers.ModelSerializer):
profile_image = serializers.FileField(required=False, write_only=True)
profile_photo = serializers.ReadOnlyField()
class Meta:
model = User
fields = ('email', 'first_name', 'last_name', 'city', 'description', 'profile_photo', 'profile_image')
def __init__(self, *args, **kwargs):
super(UserUpdateSerializer, self).__init__(*args, **kwargs)
self.fields['email'].required = False
self.fields['description'].required = False
def update(self, instance, validated_data):
if instance.id == self.context['request'].user.id:
instance.email = validated_data.get('email', instance.email)
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.city = validated_data.get('city', instance.city)
instance.description = validated_data.get('description', instance.description)
uploaded_file = validated_data.get('profile_image', None)
if uploaded_file:
validate_extension(uploaded_file.name)
instance.profile_photo = handle_uploaded_file(uploaded_file)
instance.save()
return instance
We have solved the bug!

Generating django admin and foreignkey error

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

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