There is a model Provider. It has the field role, which has two options: Individual and Organization. There are summary field and organization field.
It is necessary that in the form (in the template), in the select, the data is displayed in the following way: if the record is associated with Individual, then summqry + user, and if with the Organization, then the Organization title.
models.py
ROLE_INDIVIDUAL = 'individual'
ROLE_ORGANIZATION = 'organization'
ROLE_CHOICES = (
(ROLE_INDIVIDUAL, _('Individual')),
(ROLE_ORGANIZATION, _('Organization'))
)
class Provider(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
role = models.CharField(max_length=255, choices=ROLE_CHOICES, default=ROLE_INDIVIDUAL)
summary = models.CharField(max_length=255, default='')
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
forms.py
class ProductCreateForm(forms.ModelForm):
class Meta:
model = Product
fields = (..., 'on_behalf', ...)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('initial').get('request')
super(ProductCreateForm, self).__init__(*args, **kwargs)
self.fields['on_behalf'] = ModelChoiceField(queryset=Provider.objects.filter(user=user.id))
You should define the __str__ method on Provider to return the string you want.
class Provider(models.Model):
...
def __str__(self):
if self.role == ROLE_INDIVIDUAL:
return '{} + {}'.format(self.summary, self.user)
else:
return self.organization.title
Related
my question is i want to show only particular titles under music_track (musicmodel)field when type = track(title model) in my django admin site
class album(models.Model):
def get_autogenerated_code():
last_id = album.objects.values('id').order_by('id').last()
if not last_id:
return "AL-"+str(0)
return "AL-"+str(last_id['id'])
album_name = models.CharField( max_length=150, blank=False )
music_track = models.ManyToManyField("title")
def __str__(self):
return (self.album_name)
class Meta:
verbose_name = "Album"
verbose_name_plural = "Albums"
class title(models.Model):
def get_autogenerated_code():
last_id = title.objects.values('id').order_by('id').last()
if not last_id:
return "TT-"+str(0)
return "TT-"+str(last_id['id'])
upc_code = models.CharField(max_length=15, default="N/A", blank=False)
display_name = models.CharField(max_length=150, blank=False)
type = models.ForeignKey(Asset_Type, on_delete=models.CASCADE, null=True)
def __str__(self):
return (self.display_name+ " " +self.code)
admin.site.register( [album, title] )
From your question, I am understanding that while creating an album in your admin panel, you require that the music_track should only show the titles having type as track. My solution for this is:
In your admin.py file
from .models import title, album, Asset_type
class AlbumForm(forms.ModelForm):
class Meta:
model = Product
fields = ('album_name', 'music_track', )
def __init__(self, user, *args, **kwargs):
super(AlbumForm, self).__init__(*args, **kwargs)
type = Asset_type.objects.get(type='track')
self.fields['music_track'].queryset = Title.objects.filter(type=type)
class MyModelAdmin(admin.ModelAdmin):
form = AlbumForm
admin.site.register(album, MyModelAdmin)
Maybe this can give you the idea you need.
I am trying to create a form in Admin site that uses two fields from two different tables (Employee, Product) as input (single select & multi-select) and make it available for admin user selection and write this to another table (JobQueue).
Following is my code.
models.py
class Employee(models.Model):
id = models.IntegerField(primary_key=True, verbose_name='Employee Code')
name = models.CharField(max_length=200, verbose_name='Employee Name')
def __str__(self):
return self.name
class Product(models.Model):
STATUS = (('New', 'New'), ('Go', 'Go'), ('Hold', 'Hold'), ('Stop', 'Stop'))
code = models.IntegerField(primary_key=True, max_length=3, verbose_name='Product Code')
name = models.CharField(max_length=100, verbose_name='Product Name')
def __str__(self):
return self.name
class JobQueue(models.Model):
emp_name = models.CharField(max_length=200, default='1001')
product_code = models.CharField(max_length=200, default='100')
admin.py:
class JobQueueAdmin(admin.ModelAdmin):
form = JobQueueForm
fieldsets = (
(None,{'fields': ('emp_name', 'product_code'),}),)
def save_model(self, request, obj, form, change):
super(JobQueueAdmin, self).save_model(request, obj, form, change)
forms.py:
class JobQueueForm(forms.ModelForm):
# Single select drop down
emp_name = forms.ModelChoiceField(queryset=Employee.objects.all(), widget=forms.ChoiceField())
# Multiselect checkbox
product_code = forms.MultiValueField(queryset=Product.objects.all(), widget=forms.CheckboxSelectMultiple(), required=False)
def save(self, commit=True):
return super(JobQueueForm, self).save(commit = commit)
class Meta:
model = JobQueue
fields = ('emp_name', 'product_code')
When I start the web-server, I get the following error:
AttributeError: 'ModelChoiceField' object has no attribute 'to_field_name'
Could someone please help me how do I let the user to pick the values from JobQueueForm and save the same in JobQueue table ?
I am creating a Non Disclosure Agreement form that a user fills out after registering and logging in. I am using a custom signup form with AllAuth and pre-populating parts of the form. I pre-populate the first and last name into the top part of the form as shown below in first screen shot, but as a part of the digital signature I am setting up; I need to validate the typed signature field matches the name of the first_name and the last_name concatenated together per the second screen-shot. I know I need to setup a validator based on Django Form & Field Validations and I've tried several things but just can't get my mind rapped around it. Any help putting this together would be huge...thank you.
My Models
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile", verbose_name="user")
...
class NonDisclosure(Timestamp):
profile = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="nda", verbose_name="profile")
user_signature = models.CharField(max_length=250, verbose_name='Signature')
user_street = models.CharField(max_length=250, verbose_name='Street Address')
user_city = models.CharField(max_length=250, verbose_name='City')
user_state = models.CharField(max_length=2, verbose_name='State Initials')
user_zip = models.IntegerField(verbose_name='Zip Code')
phone = models.CharField(max_length=25, verbose_name='Phone Number')
cash_on_hand = models.CharField(max_length=250, verbose_name='Cash on Hand')
value_of_securities = models.CharField(max_length=250, verbose_name='Value of Securities')
equity_in_real_estate = models.CharField(max_length=250, verbose_name='Equity on Real Estate')
other = models.CharField(max_length=250, verbose_name='Other Assets')
#property
def username(self):
return self.profile.username
#property
def first_name(self):
return self.profile.first_name
#property
def last_name(self):
return self.profile.last_name
#property
def email(self):
return self.profile.email
class Meta:
verbose_name = 'Non Disclosure Agreement'
verbose_name_plural = 'Non Disclosure Agreements'
def __str__(self):
return "%s" % self.profile
def get_absolute_url(self):
return reverse('nda_detail', args=[str(self.id)])
My Views:
class NonDisclosureForm(BaseModelForm):
cash_on_hand = forms.CharField(required=False)
value_of_securities = forms.CharField(required=False)
equity_in_real_estate = forms.CharField(required=False)
other = forms.CharField(required=False)
class Meta:
model = NonDisclosure
fields = ['user_signature', 'user_street', 'user_city', 'user_state', 'user_zip', 'phone', 'cash_on_hand', 'value_of_securities', 'equity_in_real_estate', 'other']
class NdaCreate(CreateView):
form_class = NonDisclosureForm
template_name = 'nda/nda_form.html'
def form_valid(self, form):
form.instance.profile = Profile.objects.get(user=self.request.user)
form.instance.created_by = self.request.user
return super(NdaCreate, self).form_valid(form)
Firstly, you should subclass ModelForm, not BaseModelForm. Write a clean_<fieldname> method for your user_signature field, and make sure that the value is as expected. You can access self.instance.created_by to check.
class NonDisclosureForm(ModelForm):
...
class Meta:
model = NonDisclosure
fields = ['user_signature', ...]
def clean_user_signature(self):
user_signature = self.cleaned_data['user_signature']
expected_name = '%s %s' % (self.instance.created_by.first_name, self.instance.created_by.last_name)
if user_signature != expected_name:
raise forms.ValidationError('Signature does not match')
return user_signature
Then you need to update your view so that it sets instance.created_by. You can do this by overriding get_form_kwargs.
class NdaCreate(CreateView):
def get_form_kwargs(self):
kwargs = super(NdaCreate, self).get_form_kwargs()
kwargs['instance'] = NonDisclosure(created_by=self.request.user)
return kwargs
How to set default charfield in lowercase?
This is my model:
class User(models.Model):
username = models.CharField(max_length=100, unique=True)
password = models.CharField(max_length=64)
name = models.CharField(max_length=200)
phone = models.CharField(max_length=20)
email = models.CharField(max_length=200)
def __init__(self, *args, **kwargs):
self.username = self.username.lower()
I tried the __init__ but it doesn't work. I want to make the username in lowercase every time new record saved. Thanks.
While overwriting save() method is a valid solution. I found it useful to deal with this on a Field level as opposed to the Model level by overwriting get_prep_value() method.
This way if you ever want to reuse this field in a different model, you can adopt the same consistent strategy. Also the logic is separated from the save method, which you may also want to overwrite for different purposes.
For this case you would do this:
class NameField(models.CharField):
def get_prep_value(self, value):
return str(value).lower()
class User(models.Model):
username = models.CharField(max_length=100, unique=True)
password = models.CharField(max_length=64)
name = NameField(max_length=200)
phone = models.CharField(max_length=20)
email = models.CharField(max_length=200)
Just do it in the save method. ie, override the save method of Model class.
def save(self, *args, **kwargs):
self.username = self.username.lower()
return super(User, self).save(*args, **kwargs)
signals also works
from django.db.models.signals import pre_save
#receiver(pre_save, sender=YourModel)
def to_lower(sender, instance=None, **kwargs):
instance.text = instance.text.lower() if \
isinstance(instance.text, str) else ''
In my case I had a recipient_name field that I needed to make all lower case when it is stored on DB
class LowerField(models.CharField):
def get_prep_value(self, value):
return str(value).lower()
class Recipients(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='recipients', on_delete=models.CASCADE, )
recipient_account_number = models.IntegerField()
recipient_name = LowerField(max_length=30)
recipient_bank_name = models.CharField(max_length=30)
date = models.DateTimeField(auto_now=True, verbose_name='Transaction Date')
class Meta:
ordering = ['-date']
def __str__(self):
return self.recipient_name
def get_absolute_url(self):
return reverse('recipient-detail', kwargs={'pk': self.pk})
Similarly, you can apply to another table called Transactions in your app, like this
class Transactions(models.Model):
transaction_type = (
('transfer', 'Transfer'),
)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='transactions', on_delete=models.CASCADE, )
bank_name = LowerField(max_length=50)
def save(self, force_insert=False, force_update=False):
self.YourFildName = self.YourFildName.upper()
super(YourFomrName, self).save(force_insert, force_update)
I'd like to add multiple dealers support from the dashboard following the oscar's documentation:
You’ll need to enforce creating of a StockRecord with every Product.
When a Product is created, Stockrecord.partner gets set
to self.request.user.partner (created if necessary), and hence the
connection is made
I don't know how to enforce the StockRecord creation. oscar has a dashboard that replaces the django admin, this is an excerpt(first lines) of the view used to create/update a Product:
class ProductCreateUpdateView(generic.UpdateView):
"""
Dashboard view that bundles both creating and updating single products.
Supports the permission-based dashboard.
"""
template_name = 'dashboard/catalogue/product_update.html'
model = Product
context_object_name = 'product'
form_class = ProductForm
category_formset = ProductCategoryFormSet
image_formset = ProductImageFormSet
recommendations_formset = ProductRecommendationFormSet
stockrecord_formset = StockRecordFormSet
So the Product creation view would display the StockRecord formset, but I can create/update the Product without creating a StockRecord object. I'd like to show an error message when this occurs.
StockRecord form/formset:
class StockRecordForm(forms.ModelForm):
def __init__(self, product_class, *args, **kwargs):
super(StockRecordForm, self).__init__(*args, **kwargs)
# If not tracking stock, we hide the fields
if not product_class.track_stock:
del self.fields['num_in_stock']
del self.fields['low_stock_threshold']
else:
self.fields['price_excl_tax'].required = True
self.fields['num_in_stock'].required = True
class Meta:
model = StockRecord
exclude = ('product', 'partner', 'num_allocated')
BaseStockRecordFormSet = inlineformset_factory(
Product, StockRecord, form=StockRecordForm, extra=1)
class StockRecordFormSet(BaseStockRecordFormSet):
def __init__(self, product_class, *args, **kwargs):
self.product_class = product_class
super(StockRecordFormSet, self).__init__(*args, **kwargs)
def _construct_form(self, i, **kwargs):
kwargs['product_class'] = self.product_class
return super(StockRecordFormSet, self)._construct_form(
i, **kwargs)
StockRecord model(excerpt):
class AbstractStockRecord(models.Model):
product = models.ForeignKey(
'catalogue.Product', related_name="stockrecords",
verbose_name=_("Product"))
partner = models.ForeignKey(
'partner.Partner', verbose_name=_("Partner"),
related_name='stockrecords')
partner_sku = models.CharField(_("Partner SKU"), max_length=128)
price_currency = models.CharField(
_("Currency"), max_length=12, default=settings.OSCAR_DEFAULT_CURRENCY)
price_excl_tax = models.DecimalField(
_("Price (excl. tax)"), decimal_places=2, max_digits=12,
blank=True, null=True)
price_retail = models.DecimalField(
_("Price (retail)"), decimal_places=2, max_digits=12,
blank=True, null=True)
What you want to do is ensure there is at least 1 valid formset submitted when saving the main form?