Exclude used items in a one to many relationship - django

I'm trying to realize this relationship:
-A user can have multiple social networks, but each social ONLY ONCE
-A social network can have multiple users.
I need to avoid a user choose more than one time the same social.
Is somethig that has to be done in the model, or later filtering a user choice
class Social(models.Model):
name = models.CharField(max_length=200)
link = models.CharField(max_length=200)
def __str__(self):
return self.name
class Social2User(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
social = models.ForeignKey(Social, null=True, on_delete=models.CASCADE)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['user', 'social'], name='unique_migration_host_combination'
)
]
def __str__(self):
return self.user.username + '-' + self.social.name
class UserInfos(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
bio = models.TextField(null=False)
def __str__(self):
return self.user.username
Thank you

Related

Filter queryset of django inline formset based on attribute of through model

I have a basic restaurant inventory tracking app that allows the user to create ingredients, menus, and items on the menus. For each item on a given menu, the user can list the required ingredients for that item along with a quantity required per ingredient for that item.
Menu items have a many-to-many relationship with ingredients, and are connected via an "IngredientQuantity" through table.
Here are my models:
class Ingredient(models.Model):
GRAM = 'Grams'
OUNCE = 'Ounces'
PIECE = 'Pieces'
UNIT_CHOICES = [
('Grams', 'Grams'),
('Ounces', 'Ounces'),
('Pieces', 'Pieces')
]
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=200)
unitType = models.CharField(max_length=200, choices=UNIT_CHOICES, verbose_name='Unit')
unitCost = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='Unit Cost')
inventoryQuantity = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='Quantity')
def __str__(self):
return self.name + ' (' + self.unitType + ')'
def totalCost(self):
result = self.inventoryQuantity * self.unitCost
return "{:.0f}".format(result)
class Menu(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=200)
timeCreated = models.DateTimeField(auto_now_add=True)
timeUpdated = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.name)
class MenuItem(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2)
ingredients = models.ManyToManyField(Ingredient, through='IngredientQuantity')
menu = models.ForeignKey(Menu, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.name
def itemCost(self):
relevantIngredients = IngredientQuantity.objects.filter(menuItem=self)
cost = 0
for ingredient in relevantIngredients:
cost += (ingredient.ingredient.unitCost * ingredient.ingredientQuantity)
return cost
class IngredientQuantity(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
menuItem = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
ingredientQuantity = models.IntegerField(default=0)
def __str__(self):
return str(self.ingredient)
This is a multi-user app, so when a user creates a new item on a menu and adds ingredients to it, they should only have the option of choosing ingredients they have created, not those of other users. Here is my attempt to do that in my views:
def ItemUpdate(request, pk):
item = MenuItem.objects.get(id=pk)
user = request.user
IngredientQuantityFormset = inlineformset_factory(
MenuItem, IngredientQuantity, fields=('ingredient', 'ingredientQuantity'), can_delete=True, extra=0
)
form = ItemCreateForm(instance=item)
formset = IngredientQuantityFormset(instance=item, queryset=IngredientQuantity.objects.filter(ingredient__user=user))
if request.method == 'POST':
form = ItemCreateForm(request.POST, instance=item)
formset = IngredientQuantityFormset(request.POST, instance=item, queryset=IngredientQuantity.objects.filter(ingredient__user=user))
# rest of view...
I've searched everywhere for how to implement the queryset parameter properly, but I cannot get it to work. When creating an item on a menu, the user still has the ability to choose from every ingredient in the database (including the ones created by other users). I would like the user to only be able to choose from the ingredients they themselves created.
Does anyone know how to do this properly? Thank you!
I received some guidance on Django forums and arrived at a solution which is documented below:
https://forum.djangoproject.com/t/filter-dropdown-options-in-django-inline-formset-based-on-attribute-of-through-model/13374/3

"unique = True" - Django models - Unique for each user not unique for all data submitted by everyone

I have a models in Django currently and I have made a field unique=True so that no duplicates are submitted to the database. My problem is that it extends to all users. By this I mean that User 1 should be able to submit "Example1" and "Example2" and should never be able to submit "Example1" or "Example2" again and then User2 should come along and also be able to submit "Example1" and "Example2" but they cant because User 1 already submitted it. Is there a way where I can get somewhat of a unique=True but separately for each user and not just conjoined like it is now.
Thanks in advance. Code Below.
The problem resides in type = and my users are being defined by ForeignKey also.
class Field_Repo1(models.Model):
user = models.ForeignKey(User, default=True, related_name="Field_Repo1", on_delete=models.PROTECT)
title = models.CharField(max_length=20, verbose_name='Title of Field')
type = models.CharField(max_length=200, blank=True, unique=True, null=True, verbose_name='Field')
class Meta:
ordering = ['-type']
def __str__(self):
return str(self.user) or 'NONE'
def get_absolute_url(self):
return reverse('repo1')
UPDATED CODE THAT WORKS
class Field_Repo1(models.Model):
user = models.ForeignKey(User, default=True, related_name="Field_Repo1", on_delete=models.PROTECT)
title = models.CharField(max_length=20, verbose_name='Title of Field')
type = models.CharField(max_length=22, choices=FIELDS, verbose_name='Field')
class Meta:
ordering = ['-type']
constraints = [
models.UniqueConstraint(fields=['user', 'type'], name='unique type for each user')
]
def __str__(self):
return str(self.user) or 'NONE'
def get_absolute_url(self):
return reverse('repo1')
You need to use UniqueConstraint:
class Field_Repo1(models.Model):
user = models.ForeignKey(User, default=True, related_name="Field_Repo1", on_delete=models.PROTECT)
title = models.CharField(max_length=20, verbose_name='Title of Field')
type = models.CharField(max_length=200, blank=True, unique=True, null=True, verbose_name='Field')
def __str__(self):
return str(self.user) or 'NONE'
def get_absolute_url(self):
return reverse('repo1')
class Meta:
ordering = ['-type']
constraints = [
models.UniqueConstraint(fields=['user', 'title'], name='unique title for each user')
]

How to perform query in Django

I need to filter the a particular user's bar in whcih reservations were made. I am a beginner in Django and have tried some methods which unfortunately didn't work.
models.py
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
class Bar(models.Model):
user_id = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Tables(models.Model):
table_no = models.CharField(max_length=14, unique=False)
bar = models.ForeignKey(to=Bar, on_delete=models.CASCADE)
def __str__(self):
return self.table_no
class Reservation(models.Model):
first_name = models.CharField(max_length=200)
table = models.ForeignKey(Tables, on_delete=models.CASCADE)
def __str__(self):
return self.first_name
Note: I wan to filter the reservations made in a particular user's bar
I know you might be having a hard time and its one the things you go through when you are learning..
1.Can you change this first
from
class Bar(models.Model):
user_id = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
To
class Bar(models.Model):
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50, null=True)
def __str__(self):
return self.name
2.On querying your data can you can try this since our user will already on the bar
user_bar = Bar.objects.filter("Here you specify what you wanna filter by")
Or
user_bar = Bar.objects.get(id=pk)
When I used this query filter. it worked perfectly.
reservations = Reservation.objects.filter(table__bar__user_id=request.user)
subject title: People can come to the restaurant and book a reservation filling a form which uses the Reservation model. Then the reservation is connected to a Table which is connected to a bar and the owner of the bar. Now I need to be able to filter the reservations made in each bar owner restaurant.

Django Model object creation method

I'm having two models where UserGroup model, which contains a group admin, and DetailedUser model which related to the group model, where the field user points all users in the certain UserGroup, I want to add a field that when a new user added to the group it store its date and time of user added to the particular group.
class UserGroup(models.Model):
group_admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='group_by')
group_name = models.CharField(max_length=100)
group_amount = models.PositiveSmallIntegerField()
def __str__(self):
return self.group_name
class DetailedUser(models.Model):
group = models.ForeignKey(UserGroup, on_delete=models.CASCADE, related_name='user_group')
user = models.ManyToManyField(
User, related_name='single_user')
user_added = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return f"{self.group.group_name}"
How can I done this method?
I think your model design is not correct. What you need(I think) is ManyToManyField with though. For example:
class UserGroup(models.Model):
group_admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='group_by')
group_name = models.CharField(max_length=100)
group_amount = models.PositiveSmallIntegerField()
members = models.ManyToManyField(User, through="DetailedUser")
def __str__(self):
return self.group_name
class DetailedUser(models.Model):
group = models.ForeignKey(UserGroup, on_delete=models.CASCADE, related_name='user_group')
user = models.ForeignKey(
User, related_name='single_user')
user_added = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return f"{self.group.group_name}"
Usage example:
>> group = UserGroup.objects.get(pk=1)
>> user = User.objects.first()
>> DetailedUser.objects.create(group=group, user=user)
>> group.memebers.all()

Django Model design for a basic inventory application

I am new to Django (and databases for that matter) and trying to create a simple inventory application to help learn. I've been through the tutorials and am going through some books, but I am stuck at what i think is simple, just not sure where to look or how to ask.
With an inventory application, you have your equipment which then has a manufacturer, which the equipment has a model number that only that manufacturer has. Lets say Dell Optiplex 3040. I am also using the admin console right now as well. So i would like to be able to relate equipment to a manufacturer and then also relate the equipment to the model number. It almost seems as I am needing to use the many to many field and the through field to accomplish what I am trying to do but I dont think that is the right way to do it (shown in the link below). https://docs.djangoproject.com/en/1.9/topics/db/models/#many-to-many-relationships
Below is the code I have so far. Thank you.
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
equipmentModel = models.CharField(max_length=50)
def __str__(self):
return self.equipmentModel
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
***Edit to add the updated code and the admin.py code in response question I had to answer.
#admin.py
from django.contrib import admin
# Register your models here.
from .models import Device,Department,Manufacturer,Employees, Job_Positions, EquipmentModel
class DeviceModelAdmin(admin.ModelAdmin):
list_display = ["ip", "department","model","serial_number","date_updated"]
list_filter = ["department","model","ip"]
search_fields = ["ip"]
class Meta:
model = Device
class EmployeesModelAdmin(admin.ModelAdmin):
list_display = ["employee_name_first", "employee_name_last", "employee_username", "phone"]
list_filter = ["department"]
class Meta:
model = Employees
admin.site.register(Device, DeviceModelAdmin)
admin.site.register(Department)
admin.site.register(Manufacturer)
admin.site.register(EquipmentModel)
admin.site.register(Employees, EmployeesModelAdmin)
admin.site.register(Job_Positions)
updated models.py
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
model_number = models.CharField(max_length=50)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
def __str__(self):
return self.model_number
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE,null=True)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
A many-to-many relationship is not what you want here, because any piece of equipment (I assume) can only have one manufacturer.
You do need an intermediate model which stores the model information, and you already have one in your EquipmentModel. I would suggest modifying it as follows:
class EquipmentModel(models.Model):
# This stores information about a particular model of device
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
model_number = models.CharField(max_length=50)
And then instead of having a foreign key to the manufacturer in Device, replace it with a foreign key to the equipment model:
class Device(models.Model):
# ...
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE)