How to limit add to a model in django ? i would like to create only one company on this model, only one, so if user want to add more, it s not possible.
class Company(models.Model):
name = models.CharField(max_length=64)
address = models.TextField(max_length=250)
One of solutions is to override save method on Company
class Company(models.Model):
name = models.CharField(max_length=64)
address = models.TextField(max_length=250)
def save(self, *args, **kwargs):
if Company.objects.exists():
return
super().save(*args, **kwargs)
but your question is rather short and not precise so that's probably not the way you want it to behave
Related
I have a Django model Article and after saving an instance, I want to find the five most common words (seedwords) of that article and save the article in a different model Group, based on the seedwords.
The problem is that I want the Group to be dependent on the instances of Article, i.e. every time an Article is saved, I want Django to automatically check all existing groups and if there is no good fit, create a new Group.
class Article(models.Model):
seedword_group = models.ForeignKey("Group", null=True, blank=True)
def update_seedword_group(self):
objects = News.objects.all()
seedword_group = *some_other_function*
return seedword_group
def save(self, *args, **kwargs):
self.update_seedword_group()
super().save(*args, **kwargs)
class Group(models.Model):
*some_fields*
I have tried with signals but couldn't work it out and I'm starting to think I might have misunderstood something basic.
So, to paraphrase:
I want to save an instance of a model A.
Upon saving, I want to create or update an existing model B depending on A via ForeignKey.
Honestly I couldn't understand the rationale behind your need but I guess below code may help:
def update_seedword_group(content):
objects = News.objects.all()
"""
process word count algorithm and get related group
or create a new group
"""
if found:
seedword_group = "*some_other_function*"
else:
seedword_group = Group(name="newGroup")
seedword_group.save()
return seedword_group
class Group(models.Model):
*some_fields*
class Article(models.Model):
seedword_group = models.ForeignKey("Group", null=True, blank=True)
content = models.TextField()
def save(self):
self.group = update_seedword_group(self.content)
super().save()
I write the code to edit the list of users which belong to a team. For this I create a form, as below:
class Organization(models.Model):
name = models.CharField(blank=False, verbose_name=_("Name"), help_text=_('Organization Name'), max_length=256)
class Team(models.Model):
organization = models.ForeignKey('Organization')
name = models.CharField(blank=False, verbose_name=_("Name"), help_text=_('Team Name'), max_length=256)
users = models.ManyToManyField('User', related_name='teams')
def __str__(self):
return self.name
class TeamUsersForm(forms.ModelForm):
class Meta:
model = Team
fields = ['users']
users = forms.ModelMultipleChoiceField(queryset=User.objects.filter(request.user.organization), required=False)
def clean_users(self):
users = self.cleaned_data['users']
if users.exclude(organization=request.user.organization):
raise ValidationError(_("Cannot add user from another organization"))
return users
The code above should look into request value to determine the current organization and restrict display and model store only to users from the same organization.
But the above code cannot work, because the value of request is not known at class loading time.
What do you suggest to do?
I thought of two variants:
create a local (to a function) class like the above class TeamUsersForm
dismiss using Django forms for this altogether and use more low-level API
Overide the __init__ of the TeamUsersForm and access request there.
class TeamUsersForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
self.fields['users'] = forms.ModelMultipleChoiceField(queryset=User.objects.filter(self.request.user.organization), required=False)
This implies that when you instantiate your form, you should it this way:
# somewhere in your views.py, probably
f = TeamUsersForm(request.POST, request=request)
Let's say I have a setup similar to this:
class UnitsOfMeasure(models.Model):
name = models.CharField(max_length=40)
precision = models.PositiveIntegerField()
class Product(models.Model):
name = models.CharField(max_length=100)
uom = models.ForeignKey(UnitsOfMeasure)
qty_available = models.DecimalField(max_tigits=10, decimal_places=10)
Now lets say we have a product related to Units of measure instance with precision = 2.
How can I do that qty_available would return 5.50 instead of 5.5000000000?
I know I can use property decorator, but this does not solve my problem, since I want to use qty_available as a field in forms.
Custom Field type? How can I pass and access related model instance then??
Your ideas are very appreciated!
Override the __init__ method of your model field and set the max_digits based on the related unit of measure.
class ProductForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
self.fields['qty_available'] = models.DecimalField(max_digits=10, decimal_places=self.instance.uom.precision)
class Meta:
model = Product
If it's just a presentation problem, you can use a simple_tag in your templates:
#register.simple_tag
def format_qty_available(product):
return product.qty_available.quantize(Decimal(10) ** -product.uom.precision)
class Product(models.Model):
title = models.CharField(max_length=75)
class Deal(models.Model):
product = models.ForeignKey(Product)
slug = models.SlugField(max_length=255, unique=True)
Having a similar basic setup as above, I want to generate unique slugs for each Deal instance using product title of it's deal and id of the deal itself. IE: "apple-iphone-4s-161" where 161 is the id of the deal and the text before is the title of the product.
For this, how can I overwrite the save() method of the Deal model to apply it?
Of course you can simply overwrite save() method on model (or make receiver for post_save signal).
It will be something like:
from django.template.defaultfilters import slugify
class Deal(models.Model):
product = models.ForeignKey(Product)
slug = models.SlugField(max_length=255, unique=True)
def save(self, *args, **kwargs):
super(Deal, self).save(*args, **kwargs)
if not self.slug:
self.slug = slugify(self.product.title) + "-" + str(self.id)
self.save()
But what is ugly in this solution is that it will hit database twice (it is saved two times). It is because when creating new Deal object it will not have id until you save it for the first time (and you cannot do much about it).
i've bumped at this problem and tested the jasisz solution, and got the max recursion depth exceeded error, so i've fiddle it little and this is how looks for me:
def save(self, *args, **kwargs):
if not self.id:
self.slug = slugify(self.title)
super(Node, self).save(*args, **kwargs)
You could edit this to suit your needs, it tests if this records exists, if not then it creates the slug field otherwise is update and no need for modifieng the slug field.
hope it helps.
You should not have your id in that slug field at all. The two main reasons for this are:
It creates the problem you are having
It's redundant data in the database – the id is already stored
But there is a simple solution to your problem: The only reason why the slug is stored in the database is so you can find a row by slug. But you don't need that – you have the ID. So you should do this:
class DealManager(models.Manager):
def get_by_slug(slug):
return self.get(id=slug.rsplit('-', 1)[1])
class Deal(models.Model):
product = models.ForeignKey(Product)
objects = DealManager()
#property
def slug(self):
return slugify(f'{self.name}-f{self.id}')
In your view or wherever you need to retrieve an item given a slug, you can just do Deal.objects.get_by_slug(slug).
I know this may not exactly work for your situation, but I remember bumping into a similar case. I think I had a created_at field in my model that has auto_now=True. Or something simillar
My slug would look like like this
self.slug = '%s-%s' %(
slugify(self.title),
self.created_at
)
or you can have
self.slug = '%s-%s' %(
slugify(self.title),
datetime.datetime.now()
)
just make sure that the slug max_length is long enough to include the full created_at time, as well as the title, so that you don't end up with non-unique or over max length exceptions.
Suppose I have these models (non-practical code, it's just an example):
class BaseArticle(models.Model):
title = models.CharField(max_length=512)
author = models.ForeignKey(User)
content = models.TextField()
class Meta:
abstract = True
class ArticleWithColor(BaseArticle):
color = models.CharField(max_length=512)
class ArticleTypeWithSmell(BaseArticle):
smell = models.CharField(max_length=512)
When saving an Article (Color or Smell article), I would like to check whether there are any other existing instances that have the same values for the shared fields (those being the BaseArticle fields).
In other words: how can I check whether there already exists an ArticleWithColor with the same values for the fields it has inherited from BaseArticle as the ArticleWithSmell I'm about to save?
If you just want to protect yourself from duplicating data you can use unique_together option. Otherwise use model_to_dict(from django.forms.models import model_to_dict) to take model properties and compare them. I am not sure whether it returns pk/id as part of the dict but if so you should remove it before compare.
I've updated my answer to query all the children models. That's only one way to build the models list. It depends of your use case.
You can probably do something along those lines (still not tested):
class BaseArticle(models.Model):
title = models.CharField(max_length=512)
author = models.ForeignKey(User)
content = models.TextField()
_childrens = set()
# register the model on init
def __init__(self, *args, **kwargs):
super(BaseArticle, self).__init__(*args, **kwargs)
BaseArticle._childrens.add(self.__class__)
def save(self, *args, **kwargs):
for model in BaseArticle._childrens:
query = model.objects.filter(title=self.title, author=self.author, content=self.content)
# if this Article is already saved, exclude it from the search
if self.pk and model is self.__class__:
query.exclude(pk=self.pk)
if query.count():
# there's one or more articles with the same values
do_something()
break
super(BaseArticle, self).save(*args, **kwargs)
class Meta:
abstract = True