How to relationship such a connection in django? - django

I need to implement a "end-to-end" connection between products.
like this:
I automatically put down two-way links between two products. But when I link product A to product B and product B to product C, there is no connection between A and C. It is necessary that they communicate themselves when putting down the two previous links.
Models.py
from django.db import models
class Part(models.Model):
brand = models.CharField('Производитель', max_length=100, blank=True)
number = models.CharField('Артикул', max_length=100, unique=True)
name = models.CharField('Название', max_length=100, blank=True)
description = models.TextField('Комментарий', blank=True, max_length=5000)
analog = models.ManyToManyField('self',blank=True, related_name='AnalogParts')
images = models.FileField('Главное изображение', upload_to = 'parts/', blank=True)
images0 = models.FileField('Дополнительное фото', upload_to = 'parts/', blank=True)
images1 = models.FileField('Дополнительное фото', upload_to = 'parts/', blank=True)
images2 = models.FileField('Дополнительное фото', upload_to = 'parts/', blank=True)
def __str__(self):
return str(self.number)
return self.name
class Meta:
verbose_name = 'Запчасть'
verbose_name_plural = 'Запчасти'

Your diagram looks like Parts are connected linear. The easiest way to accomplish that is to add OneToOneFields to the model it self like so:
next = models.OneToOneField('self', related_name='previous', null=True)
Then you can do something like
part = Part.object.get(name='wheel')
while part.next:
part = part.next
# At this point Part is the last part in the row
print(part)
This is the most easy way. Depending whether you have linear connections between parts only you have to adjust your fields. There is no solution to all of the graph problems unless you realize some graph structure/database which will solve common problems (I think GraphQL can do such stuff, but iam not sure). Also keep in mind that this will most probably execute one SQL query per loop iteration.

Related

How to use a ManyToMany field in django with a through model, displaying it and saving it?

I am doing a basic system in Django for a Spa that requires me to have an inventory, massages that use different quantities of product in the inventory, and then a service which will be a combination of multiple massages. So the user of the spa, which is the staff, will be able to create a service, select which massages make that service, and that will instantly trigger the subtraction of that product from the inventory. I used a many to many relation to relate the massages and the items, with a through model to save the amount used as well. My question is, what would be the best way to display this in a form so the staff can add new massages in a way where they can choose many items and their respective quantity that the massage will use? And how can i save all of this afterwards into the DB? I'm using PostgreSQL. This is how my models look right now:
class Producto(models.Model):
nombre = models.CharField(max_length=200, blank=False)
línea = models.CharField(max_length=200, blank=False)
proveedor = models.CharField(max_length=200, blank=False)
costo_mxn = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
unidad_de_medición_choices = [
("g", "g"),
("mL", "mL"),
("oz", "oz"),
]
unidad_de_medición = models.CharField(max_length=20, choices=unidad_de_medición_choices,null=True, blank=True)
cantidad_actual = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
cantidad_inicial = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
cantidad_alerta = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
fecha_de_registro = models.DateField(blank=True,null=True,default= datetime.today)
def __str__(self):
return self.nombre
class Masaje(models.Model):
nombre = models.CharField(max_length=200, blank=False)
productos = models.ManyToManyField(Producto, through='CantidadProducto',blank=True)
costo = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
duracion = models.DurationField()
descripcion = models.TextField(
max_length=500, blank=True, null=True
)
class CantidadProducto(models.Model):
masaje = models.ForeignKey(Masaje,on_delete=models.CASCADE)
producto = models.ForeignKey(Producto,on_delete=models.CASCADE)
cantidad_usada = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
Now I've been using simple forms to display other parts of the system that I've done that aren't as complex, for example the masseuse, like this:
class MasajistaForm(ModelForm):
class Meta:
model = Masajista
fields = (
'nombre',
'telefono_celular',
'fecha_de_nacimiento',
)
widgets = {
'nombre': forms.TextInput(attrs={'class':''}),
'telefono_celular': forms.TextInput(attrs={'class':''}),
'fecha_de_nacimiento': forms.SelectDateWidget(years=range(1900, 2023),months = MONTHS,attrs={'class':''},empty_label=("Año", "Mes", "Dia"))
}
With a result like
this
Now, i know it doesn't look great but that's not the problem right now, I would like it so the staff can see a form like that where you could maybe hit a plus button or something like that where a new select box would appear with a selection of the already registered items, and an input box that could be filled by hand and then saved. What would be the way to go here?

Django Many to Many Data Duplication?

Background
I'm storing data about researchers. eg, researcher profiles, metrics for each researcher, journals they published in, papers they have, etc.
The Problem
My current database design is this:
Each Researcher has many journals (they published in). The journals have information about it.
Likewise for Subject Areas
But currently, this leads to massive data duplication. Eg, the same journal can appear many times in the Journal table, just linked to a different researcher, etc.
Is there any better way to tackle this problem? Like right now, I have over 5000 rows in the journal column but only about 1000 journals.
Thank you!
EDIT: This is likely due to the way im saving the models for new data (mentioned below). Could anyone provide the proper way to loop and save hashes to models?
Model - Researcher
class Researcher(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
scopus_id = models.BigIntegerField(db_index=True) # Index to make searches quicker
academic_rank = models.CharField(max_length=100)
title = models.CharField(max_length=200,default=None, blank=True, null=True)
salutation = models.CharField(max_length=200,default=None, blank=True, null=True)
scopus_first_name = models.CharField(max_length=100)
scopus_last_name = models.CharField(max_length=100)
affiliation = models.CharField(default=None, blank=True, null=True,max_length = 255)
department = models.CharField(default=None, blank=True, null=True,max_length = 255)
email = models.EmailField(default=None, blank=True, null=True)
properties = JSONField(default=dict)
def __str__(self):
return "{} {}, Scopus ID {}".format(self.scopus_first_name,self.scopus_last_name,self.scopus_id)
Model - Journal
class Journal(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
researchers = models.ManyToManyField(Researcher)
title = models.TextField()
journal_type = models.CharField(max_length=40,default=None,blank=True, null=True)
abbreviation = models.TextField(default=None, blank=True, null=True)
issn = models.CharField(max_length=50, default=None, blank=True, null=True)
journal_rank = models.IntegerField(default=None, blank=True, null=True)
properties = JSONField(default=dict)
def __str__(self):
return self.title
How I'm currently saving them:
db_model_fields = {'abbreviation': 'Front. Artif. Intell. Appl.',
'issn': '09226389',
'journal_type': 'k',
'researchers': <Researcher: x, Scopus ID f>,
'title': 'Frontiers in Artificial Intelligence and Applications'}
# remove researchers or else create will fail (some id need to exist error)
researcher = db_model_fields["researchers"]
del db_model_fields["researchers"]
model_obj = Journal(**db_model_fields)
model_obj.save()
model_obj.researchers.add(researcher)
model_obj.save()
Here is how it works :
class Journal(models.Model):
# some fields
class Researcher(models.Model):
# some fields
journal = models.ManyToManyField(Journal)
Django gonna create a relation table :
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship
So you'll have many rows in this table, which is how it works, but journal instance and researcher instance in THEIR table will be unique.
Your error is maybe coming from how you save. Instead of :
model_obj = Journal(**db_model_fields)
model_obj.save()
Try to just do this:
model_obj = Journal.objects.get_or_create(journal_id)
This way you'll get it if it already exists. As none of your fields are unique, you're creating new journal but there's no problem cause django is generating unique ID each time you add a new journal.

How to serialize multiple models with one Serializer using DjangoRestFramework?

I have these Models all of which have PointField:
class Place(models.Model):
title = models.CharField(max_length=75, verbose_name='Заголовок')
category = models.ForeignKey(PlaceCategory, verbose_name='Категория')
...
point = geomodels.PointField(geography=True, blank=True, null=True)
...
class Event(models.Model):
title = models.CharField(max_length=75, verbose_name='Заголовок')
address = models.CharField(max_length=255, blank=True, null=True, verbose_name='Адрес')
city = models.ForeignKey(City, verbose_name='Город')
...
point = geomodels.PointField(blank=True, null=True)
...
class Meeting(models.Model):
title = models.CharField(max_length=75)
participants = models.ManyToManyField(User, related_name='participating_meetings')
...
point = geomodels.PointField(blank=True, null=True)
...
In project I have /points API url. By this url I want to return filtered set or all the points to show them on map.
I checked DRF documentation, there is example how to build Serializer for one Model, but how do I build the API view for these multiple models?
This kind of use case is typical of where you'd need to drop the default auto generated things (serializer / view) and roll your own. I would gather the data by myself, run them through a PointSerializer - might be optional - which would inherit from Serializer and return the result.

Filtering on foreign key relationship - Django

I want to find the number of articles for which a specific user has created articlehistory records.
The models for that look like this:
class Article(models.Model):
"""The basic entity of this app.)"""
documentID = models.CharField(blank=True, max_length=1000)
cowcode = models.IntegerField(blank=True, null=True)
pubdate = models.DateField(default=datetime.datetime.today)
headline = models.CharField(blank=True, max_length=1500)
source = models.CharField(blank=True, max_length=5000)
text = models.TextField(blank=True, max_length=1000000)
assignments = models.ManyToManyField(Assignment)
class Meta:
ordering = ['pubdate']
def __unicode__(self):
return self.headline
class ArticleHistory(models.Model):
"""(Modelname description)"""
article = models.ForeignKey(Article, related_name='Article History')
coder = models.ForeignKey(User, related_name='Article History')
last_updated = models.DateTimeField(default=datetime.datetime.now)
def __unicode__(self):
return self.last_updated
The way I'm trying to do this at the moment is like this:
assignment.finished_articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date), articlehistory__coder=request.user.id).count()
This doesn't work, however and exhibits another weird behaviour:
I try to do this:
for assignment in assignments:
country = assignment.country.cowcode
start_date = assignment.start_date
end_date = assignment.end_date
articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date)).select_related()
assignment.article_num = articles.count()
#assignment.finished_articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date), articlehistory__coder=request.user.id).count()
This works fine, unless I try to include finished_articles, then article_num gets shortened to one result.
It would be really great if anyone has a pointer to who to solve this.
Make use of reverse relation of ForeignKey created by parameter related_name:
Rename attribute related name to "article_history_set".
Now, it gives you easy pointer: user.article_history_set is a set of Article History objects where coder is set to this user.
Then you can find which article it is related to by doing article_history.article.
At the end, you have to get rid of repetition and get length of that list.
Here you have more about related_name attribute: https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name

Django model: manytomany with more than one object

I have an Event model. Events can have many 'presenters'. But each presenter can either 1 of 2 different types of profiles. Profile1 and Profile2. How do I allow both profiles to go into presenters?
This will be 100% backend produced. As to say, admin will be selecting "presenters".
(Don't know if that matters or not).
class Profile1(models.Model):
user = models.ForeignKey(User, null=True, unique=True)
first_name = models.CharField(max_length=20, null=True, blank=True)
last_name = models.CharField(max_length=20, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
about = models.TextField(null=True, blank=True)
tags = models.ManyToManyField(Tag, null=True, blank=True)
country = CountryField()
avatar = models.ImageField(upload_to='avatars/users/', null=True, blank=True)
score = models.FloatField(default=0.0, null=False, blank=True)
organization = models.CharField(max_length=2, choices=organizations)
class Profile2(models.Model):
user = models.ForeignKey(User, null=True, unique=True)
first_name = models.CharField(max_length=20, null=True, blank=True)
last_name = models.CharField(max_length=20, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
about = models.TextField(null=True, blank=True)
tags = models.ManyToManyField(Tag, null=True, blank=True)
country = CountryField()
avatar = models.ImageField(upload_to='avatars/users/', null=True, blank=True)
score = models.FloatField(default=0.0, null=False, blank=True)
...
class Event(models.Model):
title = models.CharField(max_length=200)
sub_heading = models.CharField(max_length=200)
presenters = ManyToManyField(Profile1, Profile2, blank=True, null=True) ?
...
# I've also tried:
profile1_presenters = models.ManyToManyField(Profile1, null=True, blank=True)
profile2_presenters = models.ManyToManyField(Profile2, null=True, blank=True)
# is there a better way to accomplish this?...
I think you have a desing problem here. In my opinion, you must think what is a Presenter and what's the different between a Presenter with "profile 1" and with "profile 2". What are you going to do with this models? Are you sure there are just two profiles? Is there any chance that, in some time from now, a different profile ("profile 3") appears? And profile 4? and profile N?
I recommend you to think again about your models and their relations. Do NOT make this decision thinking of how difficul/easy will be to handle these models from django admin. That's another problem and i'll bet that if you think your models a little bit, this won't be an issue later.
Nevertheless, i can give you some advice of how to acomplish what you want (or i hope so). Once you have think abount how to model these relations, start thinking on how are you going to write your models in django. Here are some questions you will have to answer to yourself:
Do you need one different table (if you are going to use SQL) per profile?
If you cannot answer that, try to answer these:
1) What's the difference between two different profiles?
2) Are there more than one profile?
3) Each presenter have just one profile? What are the chances that this property changes in near future?
I don't know a lot about what you need but i think the best option is to have a model "Profile" apart of your "Presenter" model. May be something like:
class Profile(models.Model):
first_profile_field = ...
second_profile_field = ...
# Each presenter have one profile. One profile can "represent"
# to none or more presenters
class Presenter(models.Model):
first_presenter_field = ....
second_presenter_field = ....
profile = models.ForeignKey(Profile)
class Event(models.Model):
presenters = models.ManyToManyField(Presenter)
....
This is just an idea of how i imagine you could design your model. Here are some links that may help you once you have design your models correctly and have answered the questions i made to you:
https://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance
https://docs.djangoproject.com/en/dev/misc/design-philosophies/#models
http://www.martinfowler.com/eaaCatalog/activeRecord.html
And to work with the admin once you decide how your design will be:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/
EDIT:
If i'm not wrong, the only difference between profile 1 and 2 fields is the "organization" field. Am i right? So i recommend you to merge both models since they are almost the same. If they have different methods, or you want to add different managers or whatever, you can use the proxy option of django models. For example, you can do this:
class Profile(models.Model):
#All the fields you listed above, including the "organization" field
class GoldenProfile(models.Model):
#you can define its own managers
objects = GoldenProfileManager()
....
class Meta:
proxy = True
class SilverProfile(models.Model):
....
class Meta:
proxy = True
This way, you can define different methods or the same method with a different behaviour in each model. You can give them their own managers, etcetera.
And the event class should stay like this:
class Event(models.Model):
title = models.CharField(max_length=200)
sub_heading = models.CharField(max_length=200)
presenters = ManyToManyField(Profile, blank=True, null=True)
Hope it helps!