Django Admin model create new instance instead of update - python

I've multiple models in my Django project but only this given below model creating another instance on update instead of save. This is happening in Django's Admin panel, not on my custom UI. When I remove my save() method then it works fine but this way I won't be able to create slug.
Does anybody know what I'm doing wrong in here
class Course(models.Model):
title = models.CharField(max_length=200)
user = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='category')
slug = models.SlugField(max_length=200, unique=True, primary_key=True, auto_created=False)
short_description = models.TextField(blank=False, max_length=60)
description = models.TextField(blank=False)
outcome = models.CharField(max_length=200)
requirements = models.CharField(max_length=200)
language = models.CharField(max_length=200)
price = models.FloatField(validators=[MinValueValidator(9.99)])
level = models.CharField(max_length=20)
application_link = models.URLField(max_length=1000, blank=True, null=True)
brochure = models.FileField(upload_to='brochures/', blank=True, null=True)
thumbnail = models.ImageField(upload_to='thumbnails/')
video_url = models.CharField(max_length=100)
is_session_available = models.BooleanField(default=False)
session_url = models.CharField(max_length=250, default='')
is_published = models.BooleanField(default=True)
created_at = models.DateTimeField(default=now)
updated_at = models.DateTimeField(default=now)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Course, self).save(*args, **kwargs)

instead of overriding save method you could do this:
admin.py
class CourseAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)}
admin.site.register(Course, CourseAdmin)

It is happening because it will generate new slug every time. You can do something like this:
def generate_slug(self):
self.slug = slugify(self.name)
def save(self, *args, **kwargs):
if not self.slug:
self.generate_slug() # This will generate slug.
return super().save(*args, **kwargs)

Related

Django unique slug field for two or more models

I have such structure:
class Category(models.Model):
name = models.CharField(max_length=255, validators=[MinLengthValidator(3)])
parent = models.ForeignKey('self', blank=True, null=True,
related_name='children',
on_delete=models.CASCADE
)
slug = models.SlugField(max_length=255, null=False, unique=True)
class Product(models.Model):
name = models.CharField(max_length=255, validators=[MinLengthValidator(3)])
to_category = models.ForeignKey(Category, on_delete=models.SET_NULL,
blank=True, null=True,
)
slug = models.SlugField(max_length=255, null=False, unique=True)
I have created one category with slug "test". When I try to create new category with slug "test" I got warning message and it is Ok. But If I try to create product with slug "test" I dont have warning and this is not good in my case. Is there a solution or method to validate slug field for uniqueness with Product and Category model?
You can override the save method for each, and then check if the given slug already exists for a product or category.
def is_slug_unique(slug):
product_exists = Product.objects.filter(slug=slug).exists()
category_exists = Category.objects.filter(slug=slug).exists()
if product_exists or category_exists:
return False
else:
return True
class Category(models.Model)
...
def save(self, *args, **kwargs):
slug_unique = is_slug_unique(self.slug)
if not slug_unique:
# do something when the slug is not unique
else:
# do something when the slug is unique
super().save(*args, **kwargs)
class Product(models.Model)
...
def save(self, *args, **kwargs):
slug_unique = is_slug_unique(self.slug)
if not slug_unique:
# do something when the slug is not unique
else:
# do something when the slug is unique
super().save(*args, **kwargs)
An idea might be to create a Slug model that stores all the slugs, optionally with a backreference to the object:
class Slug(models.Model):
slug = models.SlugField(max_length=255, primary_key=True)
Then the slugs in your models are ForeignKeys to that Slug model, and you check if such slug already exists:
from django.core.exceptions import ValidationError
class Product(models.Model):
name = models.CharField(max_length=255, validators=[MinLengthValidator(3)])
to_category = models.ForeignKey(
Category, on_delete=models.SET_NULL, blank=True, null=True
)
slug = models.ForeignKey(Slug, on_delete=models.PROTECT)
def validate_slug(self):
if self.pk is not None and Slug.objects.filter(pk=self.slug_id).exclude(
product__pk=self.pk
):
raise ValidationError('The slug is already used.')
def clean(self, *args, **kwargs):
self.validate_slug()
return super().clean(*args, **kwargs)
def save(self, *args, **kwargs):
self.validate_slug()
return super().save(*args, **kwargs)
That being said, often overlapping slugs for different entity types are allowed.

Model Query Django

I'm trying to query fields from another model in Django .
I'm able to fetch the user information using the following method
def student(self, *args, **kwargs):
std_name = Attendance.objects.get(roll=self.roll)
return std_name.name
Now I need to find the student's assigned teacher from a different table, I need to fetch it only using the student name which I got using student() as I don't have any variable in my current table to reference it to fetch that information from the new table.
def teacher(self, *args, **kwargs):
teacher_name = staff.objects.get(student=self.student)
return teacher_name.name
But the above method is not working properly and is not populating the fields in my admin.py page . Can someone help me in fixing this issue
#Attendance model
class Attendance(models.Model):
class Meta:
verbose_name = 'Attendance'
verbose_name_plural = ''Attendance''
Group = models.TextField(max_length=15, blank=True, null=True)
Year = models.IntegerField(blank=True,null=True)
roll = models.IntegerField(blank=True,null=True)
Date = models.TextField(max_length=15, blank=True, null=True)
name = models.TextField(max_length=10, blank=True, null=True)
Presence = models.TextField(max_length=15, blank=True, null=True)
def student(self, *args, **kwargs):
std_name = Attendance.objects.get(roll=self.roll)
return std_name.name
def teacher(self, *args, **kwargs):
teacher_name = staff.objects.get(student=self.student)
return teacher_name.name
#staff model
class staff(models.Model):
class Meta:
verbose_name = staff
verbose_name_plural = ''staff''
name = models.TextField(max_length=10, blank=True, null=True)
degree = models.TextField(max_length=15, blank=True, null=True)
subject = models.IntegerField(blank=True,null=True)
experience = models.IntegerField(blank=True,null=True)
student = models.TextField(max_length=15, blank=True, null=True)

How to filter the additional model in DetailView?

class Source(models.Model):
Name = models.CharField(max_length=150)`enter code here`
Address = models.CharField(max_length=150)
Office_Phone = PhoneField(blank=True, help_text='Office phone number')
Main_Contact = models.CharField(max_length=150, blank=True, null=True)
Contact_Email = models.EmailField(max_length=254, blank=True, null=True)
Contact_Phone = PhoneField(blank=True, help_text='Main Contact phone number')
Billing_Contact = models.CharField(max_length=150, blank=True, null=True)
Billing_Email = models.EmailField(max_length=254, blank=True, null=True)
Billing_Phone = PhoneField(blank=True, help_text='Billing Contact phone number')
Notes = models.CharField(max_length=250, blank=True, null=True)
def __str__(self):
return self.Name
def get_absolute_url(self):
return reverse('sources-detail', kwargs={'pk': self.pk})
class Rate(models.Model):
Source = models.ForeignKey(Source, on_delete=models.CASCADE)
Report_Type = models.ForeignKey(ReportType, on_delete=models.CASCADE)
Amount = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True)
class SourceDetailView(DetailView):
model = Source
template_name = 'intake/source_detail.html'
context_object_name = 'source'
def get_context_data(self, *args, **kwargs):
context = super(SourceDetailView, self).get_context_data(*args, **kwargs)
context['rates'] = Rate.objects.all.filter(***not sure what to put here***)
return context
Would it be better to filter it in the Template or do it in the View? I am able to get results if I don't filter it and just use Rate.objects.all(), and then I filter it in my template. Just think there is a better way to do this.
You can just fetch the relation in reverse:
class SourceDetailView(DetailView):
model = Source
template_name = 'intake/source_detail.html'
context_object_name = 'source'
def get_context_data(self, *args, **kwargs):
context = super(SourceDetailView, self).get_context_data(*args, **kwargs)
context['rates'] = self.object.rate_set.all()
return context
That being said, here it does not make much difference to make the query in the template, since there is only one object here, so there is no N+1 problem.

filter choices for many to many field in modelform django

i want to filter the many to many field in modelform.
class IdealBehaviour(models.Model):
cbs_role = models.ManyToManyField(CbsRole, null=True, blank=True)
cbs = models.ForeignKey('cbs.CBS', null=True, blank=True)
ideal_behaviour = models.CharField(max_length=500, null=True, blank=True)
Description = models.CharField(max_length=1000, null=True, blank=True)
created_time = models.DateTimeField(auto_now_add = True,null=True, blank=True)
class StandardWork(models.Model):
cbs_and_role = models.ManyToManyField('userdata.CbsRole', null=True, blank=True)
standard_work_number = models.BigIntegerField(null=True, blank=True)
system_name= models.CharField(max_length=500, null=True, blank=True)
system_description=models.TextField(null=True, blank=True)
ideal_behaviour = models.ManyToManyField ('userdata.IdealBehaviour', null=True, blank=True)
publish = models.BooleanField(default=False)
created_time = models.DateTimeField(auto_now_add = True,null=True, blank=True)
class TodoListForm(ModelForm): # used in manage view
class Meta:
model = StandardWork
exclude = ('publish', 'cbs_and_role', 'standard_work_number')
widgets = {
'system_description': forms.Textarea(attrs={'rows':3}),
}
i want to display the choices of ideal_behaviour for the query
cbsobject = CBS.objects.get(id=dat)
idealbehaviour = IdealBehaviour.objects.filter(cbs=cbsobject)
I want to choices for ideal_behaviour in TodoListForm as idealbehaviour only.
How can i query to display ideal-behaviour assosciated with that perticuler cbs only in modelform?
i got the solution
def __init__(self, *args, **kwargs):
super(PollForm, self).__init__(*args, **kwargs)
if self.instance:
print "printing in form"
print self.instance.id
self.fields['ideal_behaviour'].queryset = IdealBehaviour.objects.filter(cbs__exact=self.instance.id)
but i dont how to get the id for cbs. self.instance.id its giving for standardwork id. i want id for cbs. i.e cbsobject i want in form as a instance. after that its working fine.
Got the solution.
I don't know if it is feasible or not, but I put the forms in the views file only so I can get the instance for "cbsobject".
class PollForm(forms.ModelForm): # used in manage view
class Meta:
model = StandardWork
exclude = ('cbs_and_role','publish', 'standard_work_number')
widgets = {
'system_description': forms.Textarea(attrs={'rows':3}),
}
def __init__(self, *args, **kwargs):
super(PollForm, self).__init__(*args, **kwargs)
if self.instance:
print "printing in form"
print self.instance.id
self.fields['ideal_behaviour'].queryset = IdealBehaviour.objects.filter(cbs__exact=cbsobject)

Custom model not being saved

I have 2 class Snippet , Comment . Error : when i try to create a snippet object , comment object is always created with default comment object not the one i specify .
s = Snippet()
s.comm.title = "Jello"
s.save()
this doesn't work:
ss = Snippets.objects.all()[0].comm.title
return's "default title" not "Jello".
class Comment(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(
max_length=100,
blank=True,
default='default comment')
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES,
default='python',
max_length=100)
style = models.CharField(choices=STYLE_CHOICES,
default='friendly',
max_length=100)
comm = Comment()
def save(self, *args, **kwargs):
self.comm.save()
super(Snippet, self).save(*args, **kwargs)
You should be using models.ForeignKey for the comm field in the Snippet model. You can read more about models.ForeignKey in this link.
So your Snippet model should look something like this
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES,
default='python',
max_length=100)
style = models.CharField(choices=STYLE_CHOICES,
default='friendly',
max_length=100)
comm = models.ForeignKey(Comment)
def save(self, *args, **kwargs):
self.comm.save()
super(Snippet, self).save(*args, **kwargs)

Categories

Resources