Limiting the number of records - django

I have one question, the answer I cant find in Google.
So, I have the model of cars (only char fields) and model of pictures of that cars:
class Pictures(models.Model):
car = models.ForeignKey(Car,related_name='pictures')
path = models.CharField(max_length=255)
about = models.CharField(max_length=32)
main = models.BooleanField('Main Picture')
def __unicode__(self):
return str(self.id)
Its possible to do the following: I want only 4 pictures for one car. For example, BMW X5 - has only 4 pictures, and I cant add 5 pictures (from the admin interface). One car - 4 pictures (max). Its possible?
As you can see, I have field main, picture with this field=1 will apear in gallery, like a start picture in slide show. But I can add main=1 for all pictures, and its wrong. So, its possible do the following:
1 car = 3 pictures(main=0) + 1 picture(main=1)
One car has 4 positions (max) in pictures table (4 pictures), and only one of that pictures has main=1. In admin interface I can add many pictures for one car and add main=1 for all pictures. How it can be limited?
Thanks

class MyModelAdmin(admin.ModelAdmin):
...........
def has_add_permission(self, request):
count = Pictures.objects.filter(main=True).count()
if count <= 4:
return True
return False

Validate your model with a custom form and clean method.
model.py:
class Image(models.Model):
image = models.ImageField(upload_to='images/%Y/%m/%d', ...)
main = models.BooleanField()
# Distinguish between main and normal images
def __unicode__(self):
if self.main:
return "%s (main)" %self.image
else:
return self.image
class Car(models.Model):
...
images = models.ManyToManyField(Image, blank=True, null=True,
related_name="%(app_label)s_%(class)s_related",
help_text="Max 1 main image and max 4 images total.")
Then in your admin.py create a ModelForm with custom clean method:
from django import forms
from django.contrib import admin
from models import Image, Car
class CarAdminForm(forms.ModelForm):
class Meta:
model = Car
def clean_images(self):
data = self.cleaned_data['images']
if data.count() > 4:
raise forms.ValidationError("Max 4 images.")
if data.filter(main=True).count() > 1:
raise forms.ValidationError("Max 1 main image.")
return data
class CarAdmin(admin.ModelAdmin):
form = CarAdminForm
filter_horizontal = ['images', ]
...
admin.site.register(Car, CarAdmin)
Bonus: to make a main image required:
if not data.filter(main=True).count() == 1:
raise forms.ValidationError("Exact 1 main image required!")

Related

How to save the number of child paragraph in Django Model?

im beginner in django. Here im trying to save number like as MS word headings 1,2,3 levels.
This model would save each paragraph items with numbers
For example if there is no uplevel, numbers should be 1, 2, 3 else 1.1, 1.2 or 1.1.1, 1.1.2
But i can't do this. Please help me.
models
class Document (models.Model):
drafttype=models.ForeignKey(DraftType, on_delete=models.CASCADE,verbose_name='GroupItem')
draft=models.CharField(max_length=500)
number=models.CharField(max_length=500)
uplevel=models.ForeignKey('self', on_delete=models.CASCADE, related_name='+')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('doc-detail', args=[str(self.id)])
def get_update_url(self):
return '/doc/update/{}'.format(self.id)
def get_delete_url(self):
return '/doc/del/{}'.format(self.id)
def save(self):
**Problem in here**
if self.uplevel:
counter=Document.objects.filter(uplevel=self.uplevel)
# increasing by 1 , should be 1.1, or 1.1.1
self.number=counter.number+'.'+counter.count()
else:
# getting last number and next one should be 2 or 3
counter=Document.objects.all().order_by('number').last()
self.number=counter.number+1
Im tried separated model as like below. But i think this is not solution
Models
class Buleg (Authors):
norm=models.ForeignKey(Norm, on_delete=models.CASCADE, verbose_name='Төсөл')
text = models.TextField(verbose_name='Бүлэг')
class Heseg (Authors):
norm=models.ForeignKey(Buleg, on_delete=models.CASCADE, verbose_name='Бүлэг')
text = models.TextField(verbose_name='Хэсэг')
class Zaalt (Authors):
norm=models.ForeignKey(Heseg, on_delete=models.CASCADE, verbose_name='Хэсэг')
text = models.TextField(verbose_name='Заалт')

How to our-ride Djangorestframework serializers.save() method for creating multiple model object on single request

I want to create multiple model object on single request, each one has its own unique id
models.py
class DemoUserRequested(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(settings.AUTH_USER_MODEL,related_name="profile",verbose_name=("user"))
name_of_obj = models.CharField(max_length=254, blank=True)
count_of_obj = models.CharField(max_length=254, blank=True)
Uuid = models.CharField(max_length=254, blank=True,null=True)# i am generating the unique id
serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
# user = UserSerializer('user', read_only=True)
class Meta:
model = DemoUserRequested
fields = ('id','name_of_obj','count_of_obj','Uuid')
read_only_fields=('id','Uuid') # i'll generating the unique id
def __unicode__(self):
return self.name_of_obj
views.py
def perform_create(self,serializer):
serializer = serializer.UserProfileSerializer(data=self.request.data)
if serializer.is_valid():
# Cheking how meny objects user want create
count = serializer.validated_data.get('count_of_obj', 1)
#if user choose to create 4 objcts I want run this loop crate 4 model objects
#this example count = 4
for x in range(count):
unic_id = uuid.uuid4()
#I want create 4 objects
serializer.save(Uuid=unic_id)
But every time i run this code it's our riding single model instance and updating 4 time's, and end-up creating one object . How can i solve this?
is this possible to do in djangorestframework ?
I've figured it out. It's very easy to do. I've got it working by doing this
def perform_create(self, serializer):
serializer = serializer.UserProfileSerializer(data=self.request.data)
if serializer.is_valid():
# Checking how many objects user want create
count = serializer.validated_data.get('count_of_obj', 1)
#if user choose to create 4 objects I want run this loop crate 4 model objects
#this example count = 4
for x in range(count):
unic_id = uuid.uuid4()
#I want create 4 objects
userobt = DemoUserRequested(
name_of_obj=serializer.validated_data['name_of_obj'],
Uuid = unic_id
)
userobt.save()
That simple :)

Django admin doesn't list models object but the count show there is

I have a simple model
class Professeurs(Metadata):
nom = models.CharField(max_length=255)
prenom = models.CharField(max_length=255)
biographie = models.TextField()
#photo = models.ForeignKey(image_model,blank=True)
photo = models.OneToOneField(Photo,primary_key=True,blank=True)
def __unicode__(self):
return "%s %s" % (self.nom, self.prenom)
which is registerd in the admin like that
class general(admin.ModelAdmin):
class Media:
js = ('/static/js/tiny_mce/tiny_mce.js', '/static/js/tiny_mce/textareas.js',)
class ProfesseursAdmin(general):
list_display = ('prenom' , 'nom' )
fields = ['prenom','nom', 'biographie','photo']
admin.site.register(Professeurs, ProfesseursAdmin)
In django admin section you can just click on your model to see all the instance you have created of this model. The problem is when i create some "professeur" they don't show up in the report of the professeur admin panel. But the count show "3" so it see there is some object. I can not understand why they dont show up
Here is a picture of the problem
https://dl.dropboxusercontent.com/u/14828537/Chose/Admin%20django.PNG
I found the problem. I did a migration and primary keys were changed because of this field
photo = models.OneToOneField(Photo,primary_key=True,blank=True). The primary_key=True was messing with the professeur.id

django admin how to limit selectbox values

model:
class Store(models.Model):
name = models.CharField(max_length = 20)
class Admin:
pass
def __unicode__(self):
return self.name
class Stock(Store):
products = models.ManyToManyField(Product)
class Admin:
pass
def __unicode__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length = 128, unique = True)
parent = models.ForeignKey('self', null = True, blank = True, related_name='children')
(...)
def __unicode__(self):
return self.name
mptt.register(Product, order_insertion_by = ['name'])
admin.py:
from bar.drinkstore.models import Store, Stock
from django.contrib import admin
admin.site.register(Store)
admin.site.register(Stock)
Now when I look at admin site I can select any product from the list. But I'd like to have a limited choice - only leaves. In mptt class there's function:
is_leaf_node() -- returns True if
the model instance is a leaf node (it
has no children), False otherwise.
But I have no idea how to connect it
I'm trying to make a subclass: in admin.py:
from bar.drinkstore.models import Store, Stock
from django.contrib import admin
admin.site.register(Store)
class StockAdmin(admin.ModelAdmin):
def queryset(self, request):
return super(StockAdmin, self).queryset(request).filter(ihavenoideawhatfilter)
admin.site.register(Stock, StockAdmin)
but I'm not sure if it's right way, and what filter set.
UPD: This is definetely wrong way. the queryset in class StockAdmin produces list of stocks. But I need to filter product list "on stock" - still don't know how.
Edit: Completely updated this
So the queryset, is finally ok but you need to filter the products on the Stock page select box (I guess?). You can define a custom form for the Stock ModelAdmin.
class StockForm(ModelForm):
products = forms.ModelChoiceField(queryset=Products.objects.filter(lft=F('rght')-1))
class Meta:
model = Stock
class StockAdmin(admin.ModelAdmin):
form = StockForm
Botondus has the right idea, but you can't do that with annotate - that's for aggregations across related querysets. Try using extra instead:
qs = super(StockAdmin, self).queryset(request).extra(
select={ 'desc_count': '(rght-lft-1)/2' }
).filter(desc_count=0)
So far your idea is right, I'm no expert on how to filter this correctly, but if you look at mptt.models.get_descendant_count you see how the number of descendents i calculated, the leaves are those where the count is zero. I guess you will have to make this condition into raw sql!
EDIT: I just read the title of your question again right now, is it now about seectbox values or changing the queryset for the change list?

How can I add a related object to the Admin index view?

I want to be able to show if an Image has been associated with each Product from the list_display view.
I seem to be having trouble because I'm dealing with an associated object.
models.py
class ImageMain(models.Model):
"""This is the Main Image of the product"""
product = models.ForeignKey(Product)
photo = models.ImageField(upload_to='lcdtvs')
pub_date = models.DateTimeField('date published', auto_now_add=True)
class Product(models.Model):
name = models.CharField(max_length=100)
poll = models.ForeignKey(Poll)
pub_date = models.DateTimeField('date published', auto_now_add=True)
size = models.IntegerField(default=0)
admin.py
def photo_for_product(obj):
images = obj.imagemain_set.all()
return images[0].photo
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', "photo_for_product")
inlines = [DescriptionInline, FeatureInline, AffiliateInline]
def upper_case_name(self, obj):
return ("%s" % (obj.name)).upper()
def photo_for_product(self, obj):
images = self.imagemain_set.all()
return images[0].photo
admin.site.register(ImageMain)
admin.site.register(Product, ProductAdmin)
For some reason, the upper_case_name() displays fine in the list view.
The photo_for_product() just keeps displaying (None).
I also tried use pdb in the photo_for_product method, but Django doesn't like that.
I also tried to put the callable before the ModelAdmin method, however, that created a lot of errors:
ProductAdmin.list_display[1], 'photo_for_product' is not a callable or an attribute of 'ProductAdmin' or found in the model 'Product'.
It's not clear from your question exactly what you want the output to be. You say you want to know "if an image has been associated" - if so, you could try this:
def photo_for_product(self, obj):
images = self.imagemain_set.all()
if images:
return True
else:
return False
photo_for_product.boolean = True
If you want to actually see the image, you'll need to return some HTML that renders it in an img tag.
def photo_for_product(self, obj):
images = self.imagemain_set.all()
if images:
return '<img src="%s">' % images[0].photo.url
else:
return ''
photo_for_product.allow_tags = True
Write a method that returns the necessary information as a string and add the name of the method to list_displays on your admin class.
I wanted the output to be a string of the path to the image. Apparently, the issue is that images[0].photo is am ImageFieldFile and not a string.
It seems that by default, ImageFieldFile has the following attributes:
ImageFieldFile.name
ImageFieldFile.path
ImageFieldFile.url
All those attributes return unicode strings.