Django ForeignKey create - python

I want to assign many Region to the UserProfile model, how to do it?
the code
class Region(models.Model):
name = models.CharField(max_length=30)
created_at = models.DateTimeField(auto_now=True)
class UserProfile(models.Model):
user = models.OneToOneField(
region = models.ForeignKey(Region, on_delete=models.CASCADE, null=True, blank=True)

The relation you describe is not a ForeignKey, which means that a UserProfile has (at most) one related Region, but a ManyToManyField [Django-doc].
A ManyToManyField thus means that a region can be related to zero, one, or more UserProfiles, and a UserProfile can be related to zero, one, or more Regions.
You can thus change the models to:
class Region(models.Model):
name = models.CharField(max_length=30)
created_at = models.DateTimeField(auto_now=True)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
regions = models.ManyToManyField(Region)
In a relational database this is implemented by adding an extra (hidden) table with ForeignKeys to Regions and UserProfiles. But the Django ORM works in a "transparant" way and thus hides the implementation details.
See the documentation for more information on how to "populate" such relation.

from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
regions = models.ManyToManyField(Region,related_name='User')
I think this is the ideal way to implement what you need. Using ManyToManyField allows you to map userprofile object to more than one region object and vice versa.
Also, Inheriting Abstract User allows you to add region field to Django User Table, which is better than creating another table for linking user to and region field.

Related

Why is model._meta.get_fields() returning unexpected relationship column names, and can this be prevented?

Imagine I have some models as below:
class User(AbstractUser):
pass
class Medium(models.Model):
researcher = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, related_name="medium_researcher")
old_medium_name = models.CharField(max_length=20, null=True, blank=True)
class Uptake(models.Model):
material_quality = models.CharField(max_length=20, null=True, blank=True)
medium = models.ForeignKey(Medium, on_delete=models.CASCADE, blank=True, null=True, related_name="uptake_medium")
Now I have a function to return all column names to generate some overview in my HTML as such:
from database.models import Medium
MODEL_HEADERS=[f.name for f in Medium._meta.get_fields()]
MODEL_HEADERS
['uptake_medium', 'id', 'researcher', 'old_medium_name']
Why does this return uptake_medium? As this is a ForeignKey relation set within the Uptake model, it should only be present within the Uptake model right? When I review the admin models this column does not show up, neither in the db.sqlite3 model when checking Uptake, so it seems to be sort of hidden, and only show up when requested with _meta. The relationship seems to be correct... This is causing a lot of problems with my code, and it would be great if only the 'non-meta' columns only could be returned. How should I approach?
Why does this return uptake_medium? As this is a ForeignKey relation set within the Uptake model, it should only be present within the Uptake model right?
You can access the relation in reverse, for example:
my_medium.uptake_medium.all()
to obtain all Updates related to the Medium instance named medium.
You can also filter on that field, for example:
Medium.objects.filter(uptake_medium__material_quantity=42)
hence it is accessible just like any field.
You can filter with:
from django.db.models.fields.reverse_related import ManyToOneRel
[f.name for f in Medium._meta.get_fields() if not isinstance(f, ManyToOneRel)]

How to restrict a Django model to a single one-to-one relation?

I am currently building a Django app that requires two different user types and I know that storing authentication information across multiple models/tables is a bad idea.
As such, I have created a User model to handle the authentication information (username, password, etc.). I have then created two different models, one for the buyers and one for the sellers, each with their own unique fields and one-to-one relationship to the User model.
Now, I thought this would work, but the problem is that it is still possible for a different buyer and seller to have the same User relation. How can I prevent this and restrict the User model to only a single one-to-one relation?
You can use unique_together to achieve your goal like this:
class Actor(models.Model):
"""An abstract base class for Buyer and Seller"""
# We define an id file in the abstract class
# this way the id is unique for Buyer and Seller
id = models.AutoField(primary_key=True)
class Meta:
abstract = True
class Buyer(Actor):
user_id = models.ForeignKey(User, ...)
class Meta:
unique_together = ('id', 'user_id',)
class Seller(Actor):
user_id = models.ForeignKey(User, ...)
class Meta:
unique_together = ('id', 'user_id',)
With this example, one Buyer is linked to only one user and one Seller is linked to only one user too.
you can add role in actor's model and make a pre_save signal before save user in buyer or seller model

How to get relevant data from a parent model in Django?

I have 2 database tables, Prospects and Profile. They're related by a One-to-one foreign key relationship
Model.py
class Prospect(models.Model):
profile = models.OneToOneField(Profile, on_delete=models.CASCADE, null=True, blank=True, related_name="profile_prospects")
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
In my view.py
prospects = prospects[:50]
I have a QuerySet of prospects (prospects is working correctly, exactly what I want), and I would like to retrieve a QuerySet of profiles based on the database model above. I tried
profiles = Profile.objects.filter(profile_prospects__in = prospects)
It returns an error of
django.db.utils.ProgrammingError: subquery has too many columns
How can I get all the relevant profiles?
You have spaces in
profiles = Profile.objects.filter(profile_prospects__in = prospects)
Sorry, I might be confused here. But isn't the profile automatically inherited by the prospect since it's a one-to-one relationship?
When you have the prospect you should be able to get the profile like this
prospect.profile
Again, I might have gotten the question wrong.

Django: allow user to add fields to model

I am just starting with Django and want to create a model for an application.
I find Djangos feature to
- automatically define validations and html widget types for forms according to the field type defined in the model and
- define a choice set for the field right in the model
very usefull and I want to make best use of it. Also, I want to make best use of the admin interface.
However, what if I want to allow the user of the application to add fields to the model? For example, consider a simple adress book. I want the user to be able to define additional atributes for all of his contacts in the admin settings, i.e. add a fax number field, so that a fax number can be added to all contacts.
from a relational DB perspective, I would have a table with atributes (PK: atr_ID, atr_name, atr_type) and an N:N relation between atributes and contacts with foreign keys from atributes and contacts - i.e. it would result in 3 tables in the DB. right?
but that way I cannot define the field types directly in the Django model. Now what is best practice here? How can I make use of Djangos functionality AND allow the user to add aditional/custom fields via the admin interface?
Thank you! :)
Best
Teconomix
i would suggest storing json as a string in the database, that way it can be as extendable as you want and the field list can go very long.
Edit:
If you are using other damn backends you can use Django-jsonfield. If you are using Postgres then it has a native jsonfield support for enhanced querying, etc.
Edit 2:
Using django mongodb connector can also help.
I've used this approach, first seen in django-payslip, to allow for extendable fields. This provides a structure for adding fields to models, from which you can allow users to add/edit through standard view procedures (no admin hacking necessary). This should be enough to get you started, and taking a look at django-payslip's source code (see the views) also provides view Mixins and forms as an example of how to render to users.
class YourModel(models.Model):
extra_fields = models.ManyToManyField(
'your_app.ExtraField',
verbose_name=_('Extra fields'),
blank=True, null=True,
)
class ExtraFieldType(models.Model):
"""
Model to create custom information holders.
:name: Name of the attribute.
:description: Description of the attribute.
:model: Can be set in order to allow the use of only one model.
:fixed_values: Can transform related exta fields into choices.
"""
name = models.CharField(
max_length=100,
verbose_name=_('Name'),
)
description = models.CharField(
max_length=100,
blank=True, null=True,
verbose_name=_('Description'),
)
model = models.CharField(
max_length=10,
choices=(
('YourModel', 'YourModel'),
('AnotherModel', 'AnotherModel'), # which models do you want to add extra fields to?
),
verbose_name=_('Model'),
blank=True, null=True,
)
fixed_values = models.BooleanField(
default=False,
verbose_name=_('Fixed values'),
)
class Meta:
ordering = ['name', ]
def __unicode__(self):
return '{0}'.format(self.name)
class ExtraField(models.Model):
"""
Model to create custom fields.
:field_type: Connection to the field type.
:value: Current value of this extra field.
"""
field_type = models.ForeignKey(
'your_app.ExtraFieldType',
verbose_name=_('Field type'),
related_name='extra_fields',
help_text=_('Only field types with fixed values can be chosen to add'
' global values.'),
)
value = models.CharField(
max_length=200,
verbose_name=_('Value'),
)
class Meta:
ordering = ['field_type__name', ]
def __unicode__(self):
return '{0} ({1}) - {2}'.format(
self.field_type, self.field_type.get_model_display() or 'general',
self.value)
You can use InlineModelAdmin objects. It should be something like:
#models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=100)
class ContactType(models.Model):
name = models.CharField(max_length=100)
class Contact(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
contact_type = models.ForeignKey(ContactType, on_delete=models.CASCADE)
value = models.CharField(max_length=100)
#admin.py
from django.contrib import admin
class ContactInline(admin.TabularInline):
model = Contact
class PersonAdmin(admin.ModelAdmin):
inlines = [
ContactInline,
]
By the way... stackoverflow questions should contain some code. You should try to do something before asking a question.

Defining the name of a ManyToOne relationship in Django

I would like to define a django model which has many-to-one relationship with itself. It is a user profile, connected as a OneToOne field with the authentication user model. I would like to save which user (if any) was the one who referred the 'current' user to my system. This means I have the following definition:
class UserProfile(models.Model):
user = models.OneToOneField(User, blank=True, related_name='profile')
class Meta:
abstract = True
class SpecificUserProfile(UserProfile):
referrer = models.ForeignKey('self')
I saw the django defaults to naming the set of referenced models by the name of the class with a suffix _set. I believe I will be getting something along the lines of specific_user_profile_set. I would much prefer to have it named u1.referrer and u2.referred or u2.referred_set. Is there any way this can be achieved?
related_name='profile'
This is the argument to define a name for any related field, so:
class SpecificUserProfile(UserProfile):
referrer = models.ForeignKey('self', related_name='referred')

Categories