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

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='Заалт')

Related

Set a limit for forms with the same value Django

So what I want to do is to set a limit of forms with the same value. There are different activities from a foreign model to which students can apply.
I have name(naam), student number(studentnummer), activity(activiteit) and class(klas), and I want to set a limit of 10 forms with the same activity (max of people who can do the same activity) and a limit of 1 for student number (so students can only apply for one activity).
models.py
class Klas(models.Model):
klas = models.CharField(max_length=8)
def __str__(self):
return f"{self.klas}"
class Activiteit(models.Model):
titel = CharField(max_length=64)
docent = CharField(max_length=32)
icon = models.ImageField()
uitleg = models.TextField()
def __str__(self):
return f"{self.id}:{self.titel}:{self.docent}"
class Aanmelden(models.Model):
naam = CharField(max_length=32)
studentnummer = IntegerField()
klas = ForeignKey(Klas, on_delete=models.CASCADE, default=None, blank=True)
activiteit = ForeignKey(Activiteit, on_delete=models.CASCADE, default=None, blank=True)
def __str__(self):
return f"{self.id}:{self.naam}:{self.studentnummer}"
views.py
def home(request):
activiteiten = Activiteit.objects.all()
form = AanmeldenForm()
if request.method == 'POST':
form = AanmeldenForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'home.html', {
'activiteiten': activiteiten,
'form':form,
})
forms.py
class AanmeldenForm(forms.ModelForm):
class Meta:
model = Aanmelden
fields = (
'naam','studentnummer','klas','activiteit'
)
If you know how to solve this or have a better idea of doing this kind of system please let me know.
Thanks in advance!!
You probably need to have a variable inside your Aktiviteit class, such as plaatsen_beschikbaar that is initialised at 10 when you create a new instance of an Aktiviteit. Then on successful Aanmelden to an instance you reduce it by one. You need to make sure in your model that plaatsen_beschikbaar cannot be less than zero, and if someone deletes the aanmelding then increase the variable by 1. Edit: or you use a validator such as the one below to restrict Aanmelden. You could also make your model have a #property that returns the plaatsen_beschikbaar instead of using a field. On second thought, this seems like a better plan, hence this edit
To make sure a student may only have 1 Aanmelden, you could just make your studentnummer unique in your Aanmelden class. But that makes your model not future-proof if you decide in future that students may subscribe to two or three activities. In that case you need to have a foreign key relationship to Student and restrict the number of Aanmelden that a student may have using a validator like so for instance
def beperk_aanmelden(value):
if Aanmelden.objects.filter(student_id=value).count() >= 1:
raise ValidationError('Student heeft al de maximale aanmeldingen')
else:
return value
Then in your Aanmelden model:
student = ForeignKey(Student, validators=[beperk_aanmelden,])
Edit: based on your current model it would look like this:
def beperk_aanmelden(value):
if Aanmelden.objects.filter(studentnummer=value).count() >= 1:
raise ValidationError('Student heeft al de maximale aanmeldingen')
else:
return value
And in your model:
studentnummer = IntegerField(validators=[beperk_aanmelden,])
Edit 2:
To check the plaatsen_beschikbaar you could do something like this:
def beperk_activiteit(value):
if Activiteit.objects.get(activiteit_id=value).plaatsen_beschikbaar <= 0:
raise ValidationError('Activiteit heeft geen plaatsen beschikbaar meer! Kies een andere activiteit.')
Then for the field in your model:
activiteit = ForeignKey(Activiteit, on_delete=models.CASCADE, default=None, blank=True, validators=[beperk_activiteit,])
Edit 3:
For the plaatsen_beschikbaar I would do something like this. Each Activiteit has a capaciteit where you set the maximum places available. Then define an #property, which gives you a non-db calculated field which you can access just like a normal field. The difference is that it's not stored, but re-calculated each time you access it. Inside count the number of Aanmelden that have the Activiteit instance as related object. That's your number of already booked placed. Then subtract this from capaciteit and you'll have a current plaatsen_beschikbaar
class Activiteit(models.Model):
titel = CharField(max_length=64)
docent = CharField(max_length=32)
icon = models.ImageField()
uitleg = models.TextField()
capaciteit = models.IntegerField()
#property
def plaatsen_beschikbaar(self):
geboekt = Aanmelden.objects.filter(activiteit_id=self.id).count()
return self.capaciteit - geboekt
def __str__(self):
return f"{self.id}:{self.titel}:{self.docent}"

How to add sub field count to django ORM model? [duplicate]

This question already has an answer here:
How to perform a join and aggregate count in Django
(1 answer)
Closed 4 years ago.
I am trying to send sub model count information with the main model to HTML template. I have PROJECT and Companies models:
class Projects(models.Model):
name = models.CharField(max_length=255)
note = models.CharField(max_length=255, default='')
def __str__(self):
return self.name
class Companies(models.Model):
project = models.ForeignKey(Projects, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
note = models.CharField(max_length=255, default='')
def __str__(self):
return self.name
I need to show, projects have how many companies(company count):
Project name | company.no
project1 | 3
project2 | 5
Method-1 : Using a GROUP BY statement using Django ORM
from django.db.models import Count
Projects.objects.values('name').annotate(count=Count('companies'))
This is equivalant to the SQL query, SELECT name,Count('companies') as count from Projects. This will return a QuerySet as,
<QuerySet [{'name': 'project_name_1', 'count': 10}, {'name': 'project_name_2', 'count': 6}]>
Method-2 : Use #property decorator (as #Kirollos Morkos mentioned )
Hence your model became
class Projects(models.Model):
name = models.CharField(max_length=255)
note = models.CharField(max_length=255, default='')
#property
def company_count(self):
return self.companies_set.count()
def __str__(self):
return self.name
Then you'll get the comapny count in template by {{ project_obj.company_count}}
NOTE: The Method-1 is more efficent and fast, because it's being done in database level
You can use the property decorator to provider an arbitrary getter on your Project model. In your Company model, add a related_name to the project foreign key so you can get the reverse relationship:
project = models.ForeignKey(Projects, on_delete=models.CASCADE, related_name='companies')
Then, you can add a property on your Project model to get the company count:
class Projects(models.Model):
#property
def company_count(self):
return self.companies.count()
...
# Following the sample counts you gave
print(project1.company_count) # 3
print(project2.company_count) # 5
As JPG says you can use annotate. you dont need to add values queryset. see below:
from django.db.models import Count
Projects.objects.filter(<any filter apply to queryset>).annotate(company_count=Count('companies'))
you can add any field to annotation. then in your template or any code you can use this count by calling:
project.company_count
you also can add in your template
{{ project.companies_set.count }}
to get count of companies. but this method is too slow. because for each project record you have a database hit.

Simple search engine in Django. Search in html content

How to create simple search engine?
I have something like this:
def search(request):
if 'search' in request.GET:
term = request.GET['search']
if len(term) > 3:
d = Data.objects.filter(Q(content__contains=term) | Q(
desc__contains=term))
count = d.count()
return render_to_response('search_result.html', {'d': d, 'count': count}, context_instance=RequestContext(request))
return render_to_response('search_result.html', context_instance=RequestContext(request))
This is ok if I search in model but I need search in html content (I use django-chunks)
Django chunks data is stored in a model too. You can import it and filter it like any other model
class Chunk(models.Model):
"""
A Chunk is a piece of content associated
with a unique key that can be inserted into
any template with the use of a special template
tag
"""
key = models.CharField(_(u'Key'), help_text=_(u"A unique name for this chunk of content"), blank=False, max_length=255, unique=True)
content = models.TextField(_(u'Content'), blank=True)
description = models.CharField(_(u'Description'), blank=True, max_length=64, help_text=_(u"Short Description"))
class Meta:
verbose_name = _(u'chunk')
verbose_name_plural = _(u'chunks')
def __unicode__(self):
return u"%s" % (self.key,)
contains is an ok way to query if you have an extremely small dataset. It just issues a LIKE query, so it will not scale very well. If you are going to have a significant amount of data it will be a good idea to look for an engine that was created specifically for full text searching.

Auto create slug field in django 1.5 models - example from django tutorial

I am quite new to Django and I am trying to auto create a slug field in django models. So, following the django 101 tutorial, I have tried to create the slug field from the following models.py
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
slugp = models.SlugField(max_length=255, unique=True)
def __unicode__(self):
return self.question
def save(self, *args, **kwargs):
self.slugp = slugify(self.question)
super(Poll, self).save(*args, **kwargs)
and then I use the django API as follows:
from writedb.models import Poll, Choice
from django.utils import timezone
p = Poll(question="What's new?", pub_date=timezone.now())
p.save
# out: <bound method Poll.save of <Poll: What's new?>>
p.slugp
#out: u''
Whatever I do the slugp field does not seem to get populated (or is the way I am accesing it wrong? I dont seem the field being populated in the database either) - I am wondering what I am doing wrong. Any pointers would be much appreciated - and sorry if this is a 101 question.
You aren't calling the save method correctly. p.save needs to be p.save(). The former will just return the contents of the save attribute which is the method itself, where as the latter actually executes the method.

Limiting the number of records

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!")