I Have two classes: Story and XmlLink. And there is many-to-many relationship between them.
I'm trying to customize saving method of XmlLink.
Idea: when I added new xmllink-object, a new story-object (temp) creates some records in db. But also I need to customize .story in def save to replace m-to-m relations with, for example, (6,7)
class Story(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
class XmlLink (models.Model):
title = models.CharField(max_length=150)
story = models.ManyToManyField(Story)
pk = 1
def save(self):
**self.story = (6,7)**
temp = Story(title = 'temp',
content = 'testtttt',
temp.save()
super(XmlLink, self).save()
i'm tried to search some examples, and different ways to solve this, but ...
Maybe someone can simplify the procedure?
This may be of some help in how to save a M2M relationship in django: https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many.
I find that it's usually more straightforward and easier to save it directly in the view, rather than defining a save method on the model.
Also, this answer may be of help: Creating a model object with a M2M and FK relationship.
Related
I'm new to the whole Django thing and a bit lost. Sorry if the title is a bit confusing I'll try to clear things out.
So basically I have two models (Folder and Document). A Document can have a single Folder as one of its fields using a Foreign Key. Now I have another field in Document that needs to get the value of the total Document objects that share the same Folder and increase by one.
I've tried things I read on the docs (aggregation, F() objects, overriding model's save() function) as well as some answers is read here but didn't manage to get it right so I'm posting to get some help. Below is my models.py file with the two models and some comments for better understanding.
class Folder(models.Model):
category = models.IntegerField()
subCategory = models.IntegerField()
name = models.CharField(max_length= 50)
desc = models.TextField()
class Document(models.Model):
folder = models.ForeignKey(Folder, on_delete=models.CASCADE)
date_created = models.DateField()
date_added = models.DateTimeField()
#The field below needs to sum all Document objects that share
#the same folder value in the database + 1 and set it as its default value
f_no = models.IntegerField(default=lambda: Document.objects.aggegate(Count('folder')) + 1)
Thank you in advance, any leads or clues are most welcome
EDIT:
Forgot to say that all management is done via Django's admin dashboard
if this has anything to do at all with my situation. I registered both
models in admin.py and that's all. I make new Folder objects when needed
and save Documents with one specific Folder in them each time
I would recommend creating a ManyToMany relation in the Folder, and add a created Document object into the Folder's ManyToMany relation.
Models.py
class Folder(models.Model):
category = models.IntegerField()
subCategory = models.IntegerField()
name = models.CharField(max_length= 50)
desc = models.TextField()
documents = models.ManyToManyField('app.Document')
You can add can add documents to the folder by using .add() to the ManyToMany relation and the amount of documents in the relation by using .count()
ManyToMany relations are well documented here:
https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/
When you create a Document model object, it represents a single item. That single item shouldn't have a count of how many documents are in a file. The f_no you note should actually be in the Folder model.
Once you create a Document object that is related to a Folder object via ForeignKey, you can use signals to increment the f_no field that resides in the Folder object.
#receiver(post_save, sender=Document)
def increment_folder_item_count(sender, **kwargs):
# get Folder object via Document model instance folder foreignkey field
# folder.f_no += 1
# folder.save()
I have a need to create custom field, that is very similar to a ForeignKey field but has specific logic. Two main tasks are:
Each related model of this CustomForeignKey has regular ForeignKey field to the model itself and my purpose is to return one of this instances depending on some parameter (date for example). Maybe it would be more clear with some example:
class Author(models.Model):
name = models.CharField(max_length = 30)
surname = models.CharField(max_length = 60)
publication = CustomForeignKey(Publication)
class Publication(models.Model):
title = models.CharField(max_length = 50)
text = models.TextField()
date = models.DateTimeField()
source = models.ForeigKey('self', related_name='references')
I want calls to SomeAuthor.publication be performed like SomePublication.references.order_by('date').first(). Real goal is more difficult, but the sense is nearly the same.
Second thing is about lookups. When I filter objects by this CustomForeignKey, I would like to have same logic as in previous point. So Author.objects.filter(publication__title = 'Some Title') should make filtering by the fist object ordered by date from references related manager.
I read the documentation about creating custom fields in django, but there are no good examples about custom relational fields. In django.db.models.fields.related as well, I didn't find which methods should I redefine to achieve my goal. There are to_python and from_db_value, but they are used only in regular fields, not related ones.
Maybe someone had more experince with custom relational fields, so I would be tankful for any advice!
I want to implement something like the pattern which introduced in this answer. For example I have four models like this:
class Protperty(models.Model):
property_type = models.CharField(choices=TYPE_CHOICES, default='float', max_length=100)
property_name = models.CharField(max_length=100)
class FloatProperty(models.Model):
property_id = models.ForeignKey(Property, related_name='value')
value = models.FloatField(default=0.0)
class IntProperty(models.Model):
property_id = models.ForeignKey(Property, related_name='value')
value = models.IntField(default=0)
class StringProperty(models.Model):
property_id = models.ForeignKey(Property, related_name='value')
value = models.CharField(max_lenght=100, blank=True, default='')
After defining these classes, I do not know how I must implement serializer or view classes. For example for writing serializer I want to put a field value, which must be set depend of type of object currently is serialized or deserialilzed(property_type defines it).
I am new to django and rest framework too, please give me some suggestions for implementing such models and serializers.
Edit:
In general I want to construct some models that using them I able to store run time defining property with different values and able to query them further. For example I have a store and it has different goods which each one has specific property and I want to query them using a specific property.
How can I store history of ManyToManyField using django-simple-history. I used HistoricalRecords with attribute m2m_filds but it is throwing error: unexpected keyword argument 'm2m_fields'
I'm macro1 on GitHub, and I guess de facto maintainer of django-simple-history.
From your question it seems that you're just asking about general ManyToManyField support compared with other fields. The short answer is that we do not currently support it.
ManyToManyFields actually create an in-between model that represents the relationship between the two models you're working with.
If you want tracking on that relationship I would suggest making a 'through' model representing the relationship and passing that into the ManyToManyField constructor. You could then register that through model to have its history tracked. If you get errors like "unexpected keyword argument 'm2m_fields'" with that set up please open an issue in our tracker.
Even though django-simple-history does not allow to have history tables for many to many relations there is actually a way to achieve this.
What you can do is that you manually create the many to many table and instead of using djangos add and remove you simply create and delete the relations. If you look at it with an example we would have:
class Class(models.Model):
name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
history = HistoricalRecords()
class Student(models.Model):
name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
classes = models.ManyToManyField(Class)
history = HistoricalRecords()
you can manually create the many to many table with:
class Class(models.Model):
name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
history = HistoricalRecords()
class Student(models.Model):
name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
history = HistoricalRecords()
class StudentClasses(models.Model):
student = models.ForeignKey(Student)
class = models.ForeignKey(Class)
history = HistoricalRecords()
if you now use:
StudentClasses.objects.create(student=student, class=class) instead of student.classes.add(class) and delete() instead of student.classes.remove(class) you will have everything tracked in a history table and the same many to many table.
As the author of django-simple-history says this isn't possible to detect change in only specific fields because
As you already know simple-history doesn't look at the values being
saved at all. It blindly saves a new historical version on every save
or delete signal.
He also says it may be possible Field Tracker do this job.
I am creating a web application to manage robotics teams for our area. In the application I have a django model that looks like this:
class TeamFormNote(models.Model):
team = models.ForeignKey(Team, blank=True, null=True)
member = models.ForeignKey(TeamMember, blank=True, null=True)
notes = models.TextField()
def __unicode__(self):
if self.team:
return "Team Form Record: " + unicode(self.team)
if self.member:
return "Member Form Record: " + unicode(self.member)
Essentially, I want it to have a relationship with team or a relationship with member, but not both. Is there a way to enforce this?
I can only see two viable solutions. First is actually the same as #mariodev suggested in the comment which is to use Genetic foreign key. That will look something like:
# make sure to change the app name
ALLOWED_RELATIONSHIPS = models.Q(app_label = 'app_name', model = 'team') | models.Q(app_label = 'app_name', model = 'teammember')
class TeamFormNote(models.Model):
content_type = models.ForeignKey(ContentType, limit_choices_to=ALLOWED_RELATIONSHIPS)
relation_id = models.PositiveIntegerField()
relation = generic.GenericForeignKey('content_type', 'relation_id')
What that does is it sets up a generic foreign key which will allow you to link to any other model within your project. Since it can link to any other model, to restrict it to only the models you need, I use the limit_choices_to parameter of the ForeignKey. This will solve your problem since there is only one generic foreign key hence there is no way multiple relationships will be created. The disadvantage is that you cannot easily apply joins to generic foreign keys so you will not be able to do things like:
Team.objects.filter(teamformnote_set__notes__contains='foo')
The second approach is to leave the model as it and manually go into the database backend and add a db constaint. For example in postgres:
ALTER TABLE foo ADD CONSTRAINT bar CHECK ...;
This will work however it will not be transparent to your code.
This sounds like a malformed object model under the hood...
How about an abstract class which defines all common elements and two dreived classes, one for team and one for member?
If you are running into trouble with this because you want to have both referenced in the same table, you can use Generic Relations.