I can't create another ForeignKey using Django - python

I'm working on a small Django Project, I would like to create a second ForeignKey in the same model, but it doesn't work after the migration I don't see the field in my table contact,
this is my Models ( i have a Custom User Model and work fine )
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
username = models.CharField(max_length=255, unique=False, blank=True, null=True)
email = models.EmailField('email address', unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
This is my class Contact ( as you can see I try to add a foreign key called user )
from django.db import models
from list.models import List
from users.models import CustomUser
class Contact(models.Model):
list = models.ForeignKey(List, on_delete=models.DO_NOTHING, related_name="list")
user = models.ForeignKey(CustomUser, on_delete=models.DO_NOTHING, related_name="user")
greeting = models.CharField(null=True, blank=True, max_length=255)
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
title = models.CharField(null=True, blank=True, max_length=60)
company = models.CharField(null=True, blank=True,max_length=60)
phone = models.CharField(null=True, blank=True, max_length=60)
def __str__(self):
return self.first_name
What i try to do :
Each user can have Contacts
Each Contact depend on a list

I don't know if this fixes the problem but
you should not name your model field "list"
because "list" is one of python's reserved keywords. When you redefine it Unexpected things can happen

Related

In Django models, how does the foreign key field know which field to match with in the other model?

I understand what Foreign Keys do but I'm having trouble understanding why this is working in Django.
I have the Project model in 'app1/models.py' file. This model has a ForeignKey named 'owner' that links to the Profile model in my 'app2/models.py' file.
How does the 'owner' field in the Project model know it should be linking to the 'user' field in the Profile model if I'm only passing the model name to the 'owner' field? I feel like I should be passing the Profile.field or something like this in the Project model:
owner = models.ForeignKey(Profile.user, null=True, blank=True ... )
Full model code from Dennis Ivy's tutorial:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=500, blank=True, null=True)
username = models.CharField(max_length=200, blank=True, null=True)
location = models.CharField(max_length=200, blank=True, null=True)
short_intro = models.CharField(max_length=200, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_image = models.ImageField(
null=True, blank=True, upload_to='profiles/', default='profiles/user-default.png')
social_github = models.CharField(max_length=200, blank=True, null=True)
social_twitter = models.CharField(max_length=200, blank=True, null=True)
social_linkedin = models.CharField(max_length=200, blank=True, null=True)
social_youtube = models.CharField(max_length=200, blank=True, null=True)
social_website = models.CharField(max_length=200, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True,
primary_key=True, editable=False)
class Project(models.Model):
owner = models.ForeignKey(Profile, null=True, blank=True, on_delete=models.SET_NULL)
title = models.CharField(max_length=200) #null is default=False and is required
description = models.TextField(null=True, blank=True) #for a bigger field, allows null(for db)/blank(for Django get/post)
featured_image = models.ImageField(null=True, blank=True, default='default.jpg')
demo_link = models.CharField(max_length=2000)
source_link = models.CharField(max_length=2000, null=True, blank=True) #can be blank in db
tags = models.ManyToManyField('Tag', blank=True) #quotes will ref other class after this one
vote_total = models.IntegerField(default=0, null=True, blank=True)
vote_ratio = models.IntegerField(default=0, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True) #generate when model instance is created
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
Foreign key fields do not match with another field in another model. it matches with the model itself.Let's say you want to assign a profile with the name 'victor' to new project model object, it would go like this:
from app_name.model import Project, Profile
profile1=Profile.objects.filter(name='victor').first()
new_project=Project(title='project 1',demolink='demo link',owner=profile1)
here, we assigned a user object to the owner property of the project and not a field.
The Profile.User field isn't necessary.
if you want to create a customUser, i suggest you should look that up or you'll be giving yourself many problems with authentication. You'll have to create a model manager for it after which you can begin to customise. It should look like this:
from django.db import models
from django.contrib.auth.models import User, AbstractUser
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.base_user import BaseUserManager
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_user(self, username, password, **extra_fields):
"""
Create and save a User with the given username and password.
"""
if not username:
raise ValueError(_('The Username must be set'))
user = self.model(username=username, **extra_fields)
user.set_password(password)
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_active', True)
user.save()
return user
def create_superuser(self, username, password, **extra_fields):
"""
Create and save a SuperUser with the given username and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(username, password, **extra_fields)
class Profile(AbstractUser):
objects = CustomUserManager()
name = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=500, blank=True, null=True)
location = models.CharField(max_length=200, blank=True, null=True)
short_intro = models.CharField(max_length=200, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_image = models.ImageField(
null=True, blank=True, upload_to='profiles/', default='profiles/user-default.png')
social_github = models.CharField(max_length=200, blank=True, null=True)
social_twitter = models.CharField(max_length=200, blank=True, null=True)
social_linkedin = models.CharField(max_length=200, blank=True, null=True)
social_youtube = models.CharField(max_length=200, blank=True, null=True)
social_website = models.CharField(max_length=200, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True,
primary_key=True, editable=False)
The field which has primary key is referenced by default if only setting a model name to "models.ForeignKey()" as mentioned in ForeignKey.to_field:
ForeignKey.to_field
...
By default, Django uses the primary key of the related object.
...
This is the full explanation of ForeignKey.to_field:
ForeignKey.to_field
The field on the related object that the relation
is to. By default, Django uses the primary key of the related object.
If you reference a different field, that field must have unique=True.
Thanks, Viq. I have solved my confusion now. The ForeignKey specifies a model but it always connects to that model's Primary Key which is why I don't have to specify Project.title or Project.id. Then when the Review model with the ForeignKey is output it calls the Project model's str method which lists out the title. I didn't realize the str method was being called.
I didn't include the str method in my code example because i didn't think that it had anything to do with my issue but I now understand that the str method is why I am seeing Project.title instead of Project.id.
def str(self): return self.title
This is the piece of the puzzle i was missing.
https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ForeignKey.to_field
ForeignKey.to_field
The field on the related object that the relation is to. By default, Django uses the primary key of the related object. If you reference a different field, that field must have unique=True.

Django API ManyToMany on existing databse not working

at the moment I try to get recipes from my API. I have a Database with two tables one is with recipes and their ids but without the ingredients, the other table contains the ingredients and also the recipe id. Now I cant find a way that the API "combines" those. Maybe its because I added in my ingredient model to the recipe id the related name, but I had to do this because otherwise, this error occurred:
ERRORS:
recipes.Ingredients.recipeid: (fields.E303) Reverse query name for 'Ingredients.recipeid' clashes with field name 'Recipe.ingredients'.
HINT: Rename field 'Recipe.ingredients', or add/change a related_name argument to the definition for field 'Ingredients.recipeid'.
Models
from django.db import models
class Ingredients(models.Model):
ingredientid = models.AutoField(db_column='IngredientID', primary_key=True, blank=True)
recipeid = models.ForeignKey('Recipe', models.DO_NOTHING, db_column='recipeid', blank=True, null=True, related_name='+')
amount = models.CharField(blank=True, null=True, max_length=100)
unit = models.CharField(blank=True, null=True, max_length=100)
unit2 = models.CharField(blank=True, null=True, max_length=100)
ingredient = models.CharField(db_column='Ingredient', blank=True, null=True, max_length=255)
class Meta:
managed = False
db_table = 'Ingredients'
class Recipe(models.Model):
recipeid = models.AutoField(db_column='RecipeID', primary_key=True, blank=True) # Field name made lowercase.
title = models.CharField(db_column='Title', blank=True, null=True, max_length=255) # Field name made lowercase.
preperation = models.TextField(db_column='Preperation', blank=True, null=True) # Field name made lowercase.
images = models.CharField(db_column='Images', blank=True, null=True, max_length=255) # Field name made lowercase.
#ingredients = models.ManyToManyField(Ingredients)
ingredients = models.ManyToManyField(Ingredients, related_name='recipes')
class Meta:
managed = True
db_table = 'Recipes'
When there is no issue it has to be in the serializer or in the view.
Serializer
class IngredientsSerializer(serializers.ModelSerializer):
# ingredients = serializers.CharField(source='ingredients__ingredients')
class Meta:
model = Ingredients
fields = ['ingredient','recipeid']
class FullRecipeSerializer(serializers.ModelSerializer):
ingredients = IngredientsSerializer(many=True)
class Meta:
model = Recipe
fields = ['title','ingredients']
View
class FullRecipesView(generics.ListCreateAPIView):
serializer_class = FullRecipeSerializer
permission_classes = [
permissions.AllowAny
]
queryset = Recipe.objects.all()
This is at the moment my output
But I want e.g. the recipe with id 0 and all the ingredients which have also recipe id 0.
I really hope that you can help me. Thank you so much!
Rename ingredients to some other name in FullRecipeSerializer. It conflicts with ingredients in Recipe model. This should solve your issue. For example
class FullRecipeSerializer(serializers.ModelSerializer):
ingredients_recipe = IngredientsSerializer(many=True, source= 'ingredientid')
class Meta:
model = Recipe
fields = ['title','ingredients_recipe']

How to show all group content if user is a group member

i am new to programming and doing a small project(simple bug tracker) using django-rest-framework.
so far i have a Bugs model and if the user is logged in, he can see the bugs reported by him.Now i created a new model called Team in which one can make a team by adding email ids (i used MultiEmailField to store the list of emails).My requirement is that if the logged in user's email is present in any Team, the user should be able to see all the team members activities.I dont know how to accomplish this .please help me.Thanks in advance
#bugs model#
from django.db import models
from django.contrib.auth.models import User
class Bugs(models.Model):
issueId = models.PositiveIntegerField(primary_key=True)
projectName = models.CharField(max_length=300)
name = models.CharField(max_length=100)
email = models.EmailField(max_length=100, unique=True)
description = models.TextField(max_length=3000, blank=True)
actualResult = models.TextField(max_length=1000, blank=True)
expectedResult = models.TextField(max_length=1000, blank=True)
status = models.TextField(max_length=30, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(
User, related_name="bugs", on_delete=models.CASCADE, null=True)
#team model#
from django.db import models
from multi_email_field.fields import MultiEmailField
from django.contrib.auth.models import User
class Team(models.Model):
projectTitle = models.CharField(max_length=300, blank=False, null=True)
durationFrom = models.DateField(null=True)
durationEnd = models.DateField(null=True)
teamMembers = MultiEmailField()
owner = models.ForeignKey(
User, related_name="team", on_delete=models.CASCADE, null=True)
#api.py#
from bugs.models import Bugs
from rest_framework import viewsets, permissions
from .serializers import BugsSerializer
class BugsViewSet(viewsets.ModelViewSet):
permission_classes = [
permissions.IsAuthenticated
]
serializer_class = BugsSerializer
def get_queryset(self):
return self.request.user.bugs.all()
def perform_create(self, serializer):
serializer.save(owner=self.request.user)

Updating a User's skills using ManyToManyField in django

I've been stuck on this for a few days (new to django) and can't figure out how to update skills for a specific user model using a ManyToManyField, while simultaneously updating a skill model containing a list of skills. Currently when I enter a value in my SkillForm, it updates the skill model properly and creates a dropdown list of skills for a given CustomUser in the admin. However, I can't figure out how to assign a SPECIFIC skill to a particular user. Any help is appreciated.
models.py:
class Skill(models.Model):
name = models.CharField(max_length =50, null=True, default='')
def __str__(self):
return self.name
class CustomUserManager(UserManager):
pass
class CustomUser(AbstractUser):
objects = CustomUserManager()
skills = models.ManyToManyField(Skill, null=True, blank=True)
position = models.CharField(max_length =50, null=True, default='')
bio = models.CharField(max_length=300, null=True, default='')
admin.py:
class SkillsInline(admin.StackedInline):
model = CustomUser.skills.through
class SkillAdmin(admin.ModelAdmin):
inlines = [SkillsInline ,]
UserAdmin.fieldsets += ('Custom fields set', {'fields': ('position', 'bio', )}),
class CustomUserAdmin(UserAdmin):
model = CustomUser
add_form = CustomUserCreationForm
form = EditProfile
inlines = [SkillsInline ,]
admin.site.register(CustomUser, CustomUserAdmin)
forms.py:
class SkillForm(forms.ModelForm):
name = forms.CharField()
class Meta:
model = Skill
fields =('name' ,)
def clean(self):
cleaned_data = super().clean()
name = cleaned_data.get('name')
I see somes problem here :
class CustomUser(AbstractUser):
objects = CustomUserManager()
skills = models.ManyToManyField(Skill, null=True, blank=True)
position = models.CharField(max_length =50, null=True, default='')
bio = models.CharField(max_length=300, null=True, default='')
When you define an AbstractUser` class, it's mean for Django Authentification purpose, see the doc here., dont do that because it's better to have an unique entry (each user have an unique entry, so you can login each one).
In your system you dont have unique CustomUser, here is a solution IMO:
class User(AbstractUser):
email = models.EmailField(_('email'), unique=True)
class UserAction(models.Model):
objects = CustomUserManager()
user = models.ForeignKey(User, verbose_name="User")
skills = models.ManyToManyField(Skill, null=True, blank=True)
position = models.CharField(max_length =50, null=True, default='')
bio = models.CharField(max_length=300, null=True, default='')
class Skill(models.Model):
name = models.CharField(max_length =50, null=True, default='')
def __str__(self):
return self.name
You now have an unique User, a list of UserAction that have a related Skill
user = User.objects.create(email='my#email.com')
skill = Skill.objects.create(name="shadow step")
user_action = UserAction.objects.create(user=user, skill=skill, position='HERE', bio='10')
Is that what you needed ?

How to display multiple objects from fields in Django Admin

I am a bit stumped as to how I can add multiple access_token and items_ids in Django Admin. The models and apps involved are as follows. This is my first post so please forgive if it isn't in proper format.
Trans/models.py
class Exchange(models.Model):
created = models.DateTimeField()
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='token', on_delete=models.CASCADE)
access_token = models.CharField(max_length=300, blank=True, default='')
item_id = models.CharField(max_length=300, blank=True, default='')
request_id = models.CharField(max_length=300, blank=True, default='')
class Meta:
ordering = ('item_id',)
I have setup a userprofile section for the admin:
Users/models.py
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, verbose_name='user', related_name='profile', on_delete=models.CASCADE)
avatar_url = models.CharField(max_length=256, blank=True, null=True)
dob = models.DateField(verbose_name="dob", blank=True, null=True)
public_token = models.CharField(max_length=100, blank=True, null=True, verbose_name='public_token')
access_token = models.CharField(max_length=100, blank=True, null=True, verbose_name='access_token')
item_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='item_ID')
just_signed_up = models.BooleanField(default=True)
def __str__(self):
return force_text(self.user)
class Meta():
db_table = 'user_profile'
users/forms.py
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('user', 'public_token', 'access_token', 'item_id',)
users/admin.py
class UserProfileAdmin(admin.ModelAdmin):
search_fields = ('user', 'dob', 'public_token', 'access_token', 'item_id',)
ordering = ('user',)
list_select_related = ('user',)
admin.site.register(UserProfile, UserProfileAdmin)
class UserProfileAdminInline(admin.TabularInline):
model = UserProfile
I'm really just stumped as I tried making many to many field but couldnt seem to link correctly and or the process broke when testing in a sandbox environment. Any help would be greatly appreciated! In my case I need to record multiple access_tokens and item_ids for each user.
It's a little bit confusing what you are asking...particularly the way that your data model is setup....but I'm going to make a couple of assumptions in my answer (it would be helpful to better understand what you are trying to do at a high level).
I think what you are wanting to do is to be able to configure multiple Exchange objects per user profile...in which case I would set things up this way:
1. The related_name field on the FK to the user profile in the exchange model will be how you access multiple exchanges...so in this case you probably want a pluralized name.
2. To be able to edit multiple in the Django Admin you will need to setup an InlineAdmin object.
3. The CharFields that are actually ON the UserProfile will only ever be single fields...if you want multiple then you need to move them to another related object (like the Exchange model).
4. I don't think what you want here is a ManyToMany as that would imply user's would be sharing these tokens and item ids (or Exchanges?)...but maybe that is what you want...in which case you should change the ForeignKey to UserProfile from the Exchange model to a ManyToManyField. The rest of this post assumes you don't want that.
trans/models.py
from django.db import models
from django.conf import settings
class Exchange(models.Model):
class Meta:
ordering = ('item_id', )
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='exchanges', on_delete=models.CASCADE)
access_token = models.CharField(max_length=300, blank=True)
item_id = models.CharField(max_length=300, blank=True)
request_id = models.CharField(max_length=300, blank=True)
users/models.py
from django.db import models
from django.conf import settings
class UserProfile(models.Model):
class Meta:
db_table = 'user_profile'
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, verbose_name='user', related_name='profile', on_delete=models.CASCADE)
avatar_url = models.CharField(max_length=256, blank=True)
dob = models.DateField(verbose_name="dob", blank=True, null=True)
public_token = models.CharField(max_length=100, blank=True, null=True)
access_token = models.CharField(max_length=100, blank=True, null=True)
item_id = models.CharField(max_length=100, blank=True, null=True)
just_signed_up = models.BooleanField(default=True)
def __str__(self):
return force_text(self.user)
users/admin.py
from django.contrib import admin
from trans.models import Exchange
from users.models import UserProfile
class ExchangeAdminInline(admin.TabularInline):
model = Exchange
class UserProfileAdmin(admin.ModelAdmin):
inlines = (ExchangeAdminInline, )
search_fields = ('user', 'dob', 'public_token', 'access_token', 'item_id', )
ordering = ('user', )
list_select_related = ('user', )
admin.site.register(UserProfile, UserProfileAdmin)
There is a lot that you can do to configure the inlines to behave how you want...but that's the basics.

Categories