How to create form which will show fields from two models? - python

I have two models:
class Product(models.Model):
name = models.CharField(verbose_name="name", max_length=40)
cost = models.FloatField(verbose_name="price")
def __unicode__(self):
return self.name
class Shop(models.Model):
product = models.ManyToManyField(Product)
name = models.CharField(verbose_name="Nazwa", max_length=40)
budget = models.FloatField(verbose_name="kwota")
def __unicode__(self):
return self.name
I created a form
code:
class ShopForm(forms.ModelForm):
product = forms.ModelMultipleChoiceField(queryset = Product.objects.all(), widget=forms.CheckboxSelectMultiple(),required=True)
name = forms.CharField(max_length=15, label='Name')
budget = forms.FloatField()
class Meta:
model = Shop
fields = ('product','name', 'budget')
It looks like on this picture, i don't know how can i show next to name of products their price? For example:
hehe - 12$
Now i have only name, i want get cost from model "Product", anybody know how can i do it?

You can solve this in different ways:
make changes in __unicode__ method in your model
class Product(models.Model):
...
def __unicode__(self):
return u"{}({})".format(self.name, self.cost)
override init method in form
class ShopForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ShopForm, self).__init__(*args, **kwargs)
self.fields['product'].label_from_instance = lambda obj: u"%s | %s" % (obj.name, obj.cost)
create custom form field:
from django.forms.models import ModelMultipleChoiceField
class ProductModelChoiceField(ModelMultipleChoiceField):
def label_from_instance(self, obj):
return u"%s | %s" % (obj.name, obj.cost)

Related

Django getting related objects from M2M

For example, I have three Models in django:
class Car(models.Models):
range = models.DecimalField()
speed = models.DecimalField()
def __str__(self):
return self.speed
class Group_of_Cars(models.Models):
name = models.CharField()
starting_city = models. CharField()
car = models.ManyToManyField(Car)
def __str__(self):
return self.name
class Arrival_time(models.Models):
Location_of_ArrivalPoint = models.CharField()
Last_known_location_of_CarGroup = models.CharField()
Group_of_Cars = models.ForeignKey(Group_of_Cars)
def function(self):
"Get speed of the "Car" in "Group_of_Cars"
def __str__(self):
return self. Location_of_ArrivalPoint
This is an example of what I want to do, not my actual models. The idea is for the user to input a series of values for the type of "Cars" such as speed and range. I'd like "Cars" to be selected when defining parameters for "a Group_of_Cars". What I'm not sure how to do is how to get the speed of the car, for the Group_of_Cars for which I need to calculate an arrival time (Group_of_Cars consists of one type of car and I'd like 'Arrival_time' to be its own table).
Thank you for any input.
models.py
from django.db import models
# Create your models here.
class Car(models.Model):
range = models.DecimalField(decimal_places=2,max_digits=5)
speed = models.DecimalField(decimal_places=2,max_digits=5)
def __str__(self):
return str(self.speed)
class Group_of_Cars(models.Model):
name = models.CharField(max_length=50)
starting_city = models. CharField(max_length=50)
car = models.ManyToManyField(Car)
def __str__(self):
return self.name
class Arrival_time(models.Model):
Location_of_ArrivalPoint = models.CharField(max_length=50)
Last_known_location_of_CarGroup = models.CharField(max_length=50)
Group_of_Cars = models.ForeignKey(Group_of_Cars, on_delete=models.CASCADE)
def function(self):
# "Get speed of the "Car" in "Group_of_Cars"
return self.Group_of_Cars.car.all()
def __str__(self):
return self. Location_of_ArrivalPoint
In views.py
from django.shortcuts import render
from core.models import Arrival_time
from django.http import HttpResponse
# Create your views here.
def home(request):
arp = Arrival_time.objects.get(Location_of_ArrivalPoint='Newyork')
for i in arp.function():
print(i)
return HttpResponse()

Django/Graphene mutations doesn't apply

I am currently creating a GraphQL interface for my Django app, using Python-Graphene. While queries works great, mutations - not quite.
The model for Ingredient:
class Ingredient(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(editable=False)
needs_refill = models.BooleanField(default=False)
created = models.DateTimeField('created', auto_now_add=True)
modified = models.DateTimeField('modified', auto_now=True)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Ingredient, self).save(*args, **kwargs)
Here's the schema code (full code here: https://ctrlv.it/id/107369/1044410281):
class IngredientType(DjangoObjectType):
class Meta:
model = Ingredient
...
class CreateIngredient(Mutation):
class Arguments:
name = String()
ok = Boolean()
ingredient = Field(IngredientType)
def mutate(self, info, name):
ingredient = IngredientType(name=name)
ok = True
return CreateIngredient(ingredient=ingredient, ok=ok)
class MyMutations(ObjectType):
create_ingredient = CreateIngredient.Field()
schema = Schema(query=Query, mutation=MyMutations)
and my mutation:
mutation {
createIngredient(name:"Test") {
ingredient {
name
}
ok
}
}
Running it returns proper object and ok is True, but no data is pushed to the database. What should I do? What did I miss?
Close...inside your mutate method you need to save your ingredient as an instance of Ingredient (not IngredientType) and then use that to create your IngredientType object. Also, you should declare mutate as #staticmethod. Something like:
#staticmethod
def mutate(root, info, name):
ingredient = Ingredient.objects.create(name=name)
ok = True
return CreateIngredient(ingredient=ingredient, ok=ok)

adding / editing django generic foreign key objects

Model Device:
class Device(models.Model):
device_code = models.CharField(max_length=64,unique=True)
is_enabled = models.BooleanField(default=False)
def __unicode__(self):
return u'%s: %s' % (self.device_code, 'ENABLED' if self.is_enabled else 'DISABLED')
Model AttributeValues:
class AttributeValue(models.Model):
attribute = models.ForeignKey(Attribute)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Meta:
abstract = True
unique_together = (
('attribute', 'content_type','object_id'),
)
index_together = (
('content_type','object_id'),
)
#property
def formatted(self):
"""
PLEASE SELECT RELATED ATTRIBUTE BEFORE USING THIS FUNCTION
"""
return self.attribute.format % self.value
def save(self,*args,**kwargs):
if hasattr(self.content_object,'invalidate_cache') and callable(self.content_object.invalidate_cache):
self.content_object.invalidate_cache()
super(AttributeValue,self).save(*args, **kwargs)
def __unicode__(self):
return u'%s %s' % (self.attribute.name, self.value)
class NumericAttributeValue(AttributeValue):
value = models.DecimalField(max_digits=12,decimal_places=4)
class LongTextAttributeValue(AttributeValue):
value = models.TextField()
class ShortTextAttributeValue(AttributeValue):
value = models.CharField(max_length=255)
class FileAttributeValue(AttributeValue):
attribute_file = models.FileField(upload_to="attribute_imgs")
Model Attribute:
ATTRIBUTE_TYPE_CHOICES = (
('n','Numeric'),
('s','Short Text (255)'),
('m','Long Text')
)
class Attribute(models.Model):
name = models.CharField(max_length=255)
code = models.CharField(max_length=64,unique=True)
attribute_type = models.CharField(max_length=1,choices=ATTRIBUTE_TYPE_CHOICES)
sorting_order = models.PositiveIntegerField(default=0)
show = models.BooleanField(default=False)
format = models.CharField(max_length=64,default='%s')
class Meta:
ordering = ['sorting_order','name']
def __unicode__(self):
return self.name
In my device editing (adding) page, it needs to be able to create or select an attribute, then create (or edit / delete) an attribute value (could be a numeric value, long text value, short text value or a file) associated to this attribute, and the current (or new) device. How would you create a django formset for this kind of scenario?
I had to solve a similar problem and django-polymorphic worked for me.
If you define an abstract model as the parent, then it allows you to select any child models that the parent is based on in the Django admin interface (when selecting a foreign-key for example).
You will have to make some changes in your model & admin to get it working (for eg; you won't need GenericForeignKey).
https://django-polymorphic.readthedocs.org/en/latest/

Django multiple similar models

I want refactor some of my code in models because it's a little mess. I have couple models.
class Part(models.Model):
class Category(models.Model):
class Labor(models.Model):
And so on, seven in total. I am generating for them ID. For Part it is:
def save(self, *args, **kwargs):
if not Part.objects.count():
latest = 'XXX00000'
else:
latest = Part.objects.all().order_by('-par_id')[0].par_id
self.par_id = "PAR" + str(int(latest[3:]) + 1).zfill(5)
super(Part, self).save(*args, **kwargs)
And it's pretty similar for rest of classes. Only name of class is changing, three letters identification and paramtere in order_by. I was wondering how can I do it DRY. Because it's 7 lines of code on each class that should be somehow shortened.
I was wondering maybe create BaseModel class inherited from it and somehow change only mentioned things. I would like to get some directions how can I do it better.
Edit:
class Part(models.Model):
par_id = models.CharField(primary_key=True, unique=True, max_length=9, blank=False)
par_name = models.CharField(max_length=50)
def save(self, *args, **kwargs):
if not Part.objects.count():
latest = 'XXX00000'
else:
latest = Part.objects.all().order_by('-par_id')[0].par_id
self.par_id = "PAR" + str(int(latest[3:]) + 1).zfill(5)
super(Part, self).save(*args, **kwargs)
class Category(models.Model):
cat_id = models.CharField(primary_key=True, unique=True, max_length=9)
cat_name = models.CharField(max_length=50)
def save(self, *args, **kwargs):
if not Category.objects.count():
latest = 'XXX00000'
else:
latest = Category.objects.all().order_by('-cat_id')[0].cat_id
self.cat_id = "CAT" + str(int(latest[3:]) + 1).zfill(5)
super(Category, self).save(*args, **kwargs)
That are two o my classes.
Inheriting is definitely a good idea.
You're not giving much information about the models. So there are 2 main options for inheriting models:
A) To use an AbstractModel which would hold the common fields and some common methods. And then use child models to extend the fields and methods as you need. Here is an example from the django docs:
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
B) If you're only interested in inheriting or extending the behavioural parts of your models (like the different methods for generating the id's), a proxy model would be a better option. Take a look at the docs: https://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models
Here is an example taken from the django docs:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
create class BaseModel(models.Model): and copypaste your save method there, but replace Part with self.__class__ , for example
class BaseModel(models.Model):
# some fields here
class Meta:
abstract = True
def save(self, *args, **kwargs):
first_declared_field = self.__class__._meta.fields[1].name
if self.__class__.objects.count():
latest = getattr(self.__class__.objects.order_by('-' + first_declared_field)[0], first_declared_field)
else:
latest = 'XXX00000'
field_value = first_declared_field.name.split('_')[0].upper() + str(int(latest[3:]) + 1).zfill(5)
setattr(self, first_declared_field, field_value)
super(BaseModel, self).save(*args, **kwargs)
class SomeChildModel(BaseModel):
pass

How do I filter values in a Django form using ModelForm?

I am trying to use the ModelForm to add my data. It is working well, except that the ForeignKey dropdown list is showing all values and I only want it to display the values that a pertinent for the logged in user.
Here is my model for ExcludedDate, the record I want to add:
class ExcludedDate(models.Model):
date = models.DateTimeField()
reason = models.CharField(max_length=50)
user = models.ForeignKey(User)
category = models.ForeignKey(Category)
recurring = models.ForeignKey(RecurringExclusion)
def __unicode__(self):
return self.reason
Here is the model for the category, which is the table containing the relationship that I'd like to limit by user:
class Category(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User, unique=False)
def __unicode__(self):
return self.name
And finally, the form code:
class ExcludedDateForm(ModelForm):
class Meta:
model = models.ExcludedDate
exclude = ('user', 'recurring',)
How do I get the form to display only the subset of categories where category.user equals the logged in user?
You can customize your form in init
class ExcludedDateForm(ModelForm):
class Meta:
model = models.ExcludedDate
exclude = ('user', 'recurring',)
def __init__(self, user=None, **kwargs):
super(ExcludedDateForm, self).__init__(**kwargs)
if user:
self.fields['category'].queryset = models.Category.objects.filter(user=user)
And in views, when constructing your form, besides the standard form params, you'll specify also the current user:
form = ExcludedDateForm(user=request.user)
Here example:
models.py
class someData(models.Model):
name = models.CharField(max_length=100,verbose_name="some value")
class testKey(models.Model):
name = models.CharField(max_length=100,verbose_name="some value")
tst = models.ForeignKey(someData)
class testForm(forms.ModelForm):
class Meta:
model = testKey
views.py
...
....
....
mform = testForm()
mform.fields["tst"] = models.forms.ModelMultipleChoiceField(queryset=someData.objects.filter(name__icontains="1"))
...
...
Or u can try something like this:
class testForm(forms.ModelForm):
class Meta:
model = testKey
def __init__(self,*args,**kwargs):
super (testForm,self ).__init__(*args,**kwargs)
self.fields['tst'].queryset = someData.objects.filter(name__icontains="1")
I know this is old; but its one of the first Google search results so I thought I would add how I found to do it.
class CustomModelFilter(forms.ModelChoiceField):
def label_from_instance(self, obj):
return "%s %s" % (obj.column1, obj.column2)
class CustomForm(ModelForm):
model_to_filter = CustomModelFilter(queryset=CustomModel.objects.filter(active=1))
class Meta:
model = CustomModel
fields = ['model_to_filter', 'field1', 'field2']
Where 'model_to_filter' is a ForiegnKey of the "CustomModel" model
Why I like this method:
in the "CustomModelFilter" you can also change the default way that the Model object is displayed in the ChoiceField that is created, as I've done above.
is the best answer:
BookDemoForm.base_fields['location'] = forms.ModelChoiceField(widget=forms.Select(attrs={'class': 'form-control select2'}),queryset=Location.objects.filter(location_for__fuel=True))

Categories